package network.thunder.core.communication.processor.implementations; import network.thunder.core.communication.Message; import network.thunder.core.communication.objects.messages.MessageExecutor; import network.thunder.core.communication.objects.messages.impl.message.gossip.objects.ChannelStatusObject; import network.thunder.core.communication.objects.messages.impl.message.gossip.objects.PubkeyChannelObject; import network.thunder.core.communication.objects.messages.impl.message.lightningestablish.LNEstablishAMessage; import network.thunder.core.communication.objects.messages.impl.message.lightningestablish.LNEstablishBMessage; import network.thunder.core.communication.objects.messages.impl.message.lightningestablish.LNEstablishCMessage; import network.thunder.core.communication.objects.messages.impl.message.lightningestablish.LNEstablishDMessage; import network.thunder.core.communication.objects.messages.impl.results.ChannelCreatedResult; import network.thunder.core.communication.objects.messages.interfaces.factories.ContextFactory; import network.thunder.core.communication.objects.messages.interfaces.factories.LNEstablishMessageFactory; import network.thunder.core.communication.objects.messages.interfaces.helper.BlockchainHelper; import network.thunder.core.communication.objects.messages.interfaces.helper.ChannelManager; import network.thunder.core.communication.objects.messages.interfaces.helper.LNEventHelper; import network.thunder.core.communication.objects.messages.interfaces.helper.WalletHelper; import network.thunder.core.communication.objects.messages.interfaces.message.lightningestablish.LNEstablish; import network.thunder.core.communication.processor.ChannelIntent; import network.thunder.core.communication.processor.exceptions.LNEstablishException; import network.thunder.core.communication.processor.implementations.gossip.BroadcastHelper; import network.thunder.core.communication.processor.interfaces.LNEstablishProcessor; import network.thunder.core.database.DBHandler; import network.thunder.core.database.objects.Channel; import network.thunder.core.etc.Tools; import network.thunder.core.mesh.NodeClient; import network.thunder.core.mesh.NodeServer; import org.bitcoinj.core.Transaction; import org.bitcoinj.crypto.TransactionSignature; /** * Created by matsjerratsch on 03/12/2015. */ public class LNEstablishProcessorImpl extends LNEstablishProcessor { public static final double PERCENTAGE_OF_FUNDS_PER_CHANNEL = 0.1; WalletHelper walletHelper; LNEstablishMessageFactory messageFactory; BroadcastHelper broadcastHelper; LNEventHelper eventHelper; DBHandler dbHandler; NodeClient node; NodeServer nodeServer; BlockchainHelper blockchainHelper; ChannelManager channelManager; MessageExecutor messageExecutor; public Channel channel; int status = 0; public LNEstablishProcessorImpl (ContextFactory contextFactory, DBHandler dbHandler, NodeClient node) { this.walletHelper = contextFactory.getWalletHelper(); this.messageFactory = contextFactory.getLNEstablishMessageFactory(); this.broadcastHelper = contextFactory.getBroadcastHelper(); this.eventHelper = contextFactory.getEventHelper(); this.dbHandler = dbHandler; this.node = node; this.nodeServer = contextFactory.getServerSettings(); this.blockchainHelper = contextFactory.getBlockchainHelper(); this.channelManager = contextFactory.getChannelManager(); } @Override public void onInboundMessage (Message message) { try { consumeMessage(message); } catch (Exception e) { e.printStackTrace(); messageExecutor.sendMessageUpwards(messageFactory.getFailureMessage(e.getMessage())); node.resultCallback.execute(new ChannelCreatedResult(channel)); throw e; } } @Override public boolean consumesInboundMessage (Object object) { return object instanceof LNEstablish; } @Override public boolean consumesOutboundMessage (Object object) { return false; } @Override public void onLayerActive (MessageExecutor messageExecutor) { //TODO check for existing channels, check if we are still waiting for them to gather enough confirmations, ... this.messageExecutor = messageExecutor; if(dbHandler.getChannel(node.pubKeyClient.getPubKey()) != null) { messageExecutor.sendNextLayerActive(); } else { if (!node.isServer) { if (node.intent == ChannelIntent.OPEN_CHANNEL) { sendEstablishMessageA(); } } } } private void consumeMessage (Message message) { if (message instanceof LNEstablishAMessage) { processMessageA(message); } else if (message instanceof LNEstablishBMessage) { processMessageB(message); } else if (message instanceof LNEstablishCMessage) { processMessageC(message); } else if (message instanceof LNEstablishDMessage) { processMessageD(message); } else { throw new UnsupportedOperationException("Don't know this LNEstablish Message: " + message); } } private void processMessageA (Message message) { checkStatus(0); LNEstablish m = (LNEstablish) message; prepareNewChannel(); m.saveToChannel(channel); sendEstablishMessageB(); } private void processMessageB (Message message) { checkStatus(2); LNEstablish m = (LNEstablish) message; m.saveToChannel(channel); sendEstablishMessageC(); } private void processMessageC (Message message) { checkStatus(3); LNEstablish m = (LNEstablish) message; m.saveToChannel(channel); channel.verifyEscapeSignatures(); sendEstablishMessageD(); onChannelEstablished(); } private void processMessageD (Message message) { checkStatus(4); LNEstablish m = (LNEstablish) message; m.saveToChannel(channel); channel.verifyEscapeSignatures(); onChannelEstablished(); } private void onChannelEstablished () { dbHandler.saveChannel(channel); // channelManager.onExchangeDone(channel, this::onEnoughConfirmations); this.onEnoughConfirmations(); blockchainHelper.broadcastTransaction(channel.getAnchorTransactionServer()); } private void onEnoughConfirmations () { channel.initiateChannelStatus(nodeServer.configuration); dbHandler.updateChannel(channel); broadcastChannelObject(); eventHelper.onChannelOpened(channel); messageExecutor.sendNextLayerActive(); } private void sendEstablishMessageA () { prepareNewChannel(); Message message = messageFactory.getEstablishMessageA(channel); messageExecutor.sendMessageUpwards(message); status = 2; } private void sendEstablishMessageB () { Transaction anchor = channel.getAnchorTransactionServer(walletHelper); Message message = messageFactory.getEstablishMessageB(channel, anchor); messageExecutor.sendMessageUpwards(message); status = 3; } private void sendEstablishMessageC () { Transaction anchor = channel.getAnchorTransactionServer(walletHelper); Transaction escape = channel.getEscapeTransactionClient(); Transaction fastEscape = channel.getFastEscapeTransactionClient(); TransactionSignature escapeSig = Tools.getSignature(escape, 0, channel.getScriptAnchorOutputClient().getProgram(), channel.getKeyServerA()); TransactionSignature fastEscapeSig = Tools.getSignature(fastEscape, 0, channel.getScriptAnchorOutputClient().getProgram(), channel .getKeyServerA()); Message message = messageFactory.getEstablishMessageC(anchor, escapeSig, fastEscapeSig); messageExecutor.sendMessageUpwards(message); status = 4; } private void sendEstablishMessageD () { Transaction escape = channel.getEscapeTransactionClient(); Transaction fastEscape = channel.getFastEscapeTransactionClient(); TransactionSignature escapeSig = Tools.getSignature(escape, 0, channel.getScriptAnchorOutputClient().getProgram(), channel.getKeyServerA()); TransactionSignature fastEscapeSig = Tools.getSignature(fastEscape, 0, channel.getScriptAnchorOutputClient().getProgram(), channel .getKeyServerA()); Message message = messageFactory.getEstablishMessageD(escapeSig, fastEscapeSig); messageExecutor.sendMessageUpwards(message); status = 5; } private void prepareNewChannel () { channel = new Channel(node.pubKeyClient.getPubKey(), nodeServer.pubKeyServer, getAmountForNewChannel()); status = 1; } private void broadcastChannelObject () { PubkeyChannelObject channelObject = PubkeyChannelObject.getRandomObject(); ChannelStatusObject statusObject = new ChannelStatusObject(); statusObject.pubkeyA = nodeServer.pubKeyServer.getPubKey(); statusObject.pubkeyB = node.pubKeyClient.getPubKey(); broadcastHelper.broadcastNewObject(channelObject); broadcastHelper.broadcastNewObject(statusObject); } private long getAmountForNewChannel () { return (long) (walletHelper.getSpendableAmount() * PERCENTAGE_OF_FUNDS_PER_CHANNEL); } private void checkStatus (int expected) { if (status != expected) { throw new LNEstablishException("Status not correct.. Is: " + status + " Expected: " + expected); } } }