package network.thunder.core.communication.nio.handler.high; import io.netty.channel.embedded.EmbeddedChannel; import network.thunder.core.communication.Message; import network.thunder.core.communication.nio.handler.ProcessorHandler; import network.thunder.core.communication.objects.messages.impl.blockchainlistener.MockBlockchainHelper; import network.thunder.core.communication.objects.messages.impl.factories.ContextFactoryImpl; 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.interfaces.factories.ContextFactory; import network.thunder.core.communication.objects.messages.interfaces.helper.BlockchainHelper; import network.thunder.core.communication.objects.messages.interfaces.message.FailureMessage; import network.thunder.core.communication.processor.ChannelIntent; import network.thunder.core.communication.processor.exceptions.LNEstablishException; import network.thunder.core.communication.processor.implementations.LNEstablishProcessorImpl; import network.thunder.core.communication.processor.implementations.gossip.BroadcastHelper; import network.thunder.core.database.DBHandler; import network.thunder.core.database.objects.Channel; import network.thunder.core.etc.*; import network.thunder.core.mesh.NodeClient; import network.thunder.core.mesh.NodeServer; import org.bitcoinj.core.Sha256Hash; import org.bitcoinj.core.Transaction; import org.bitcoinj.crypto.TransactionSignature; import org.junit.Before; import org.junit.Test; import java.beans.PropertyVetoException; import java.sql.SQLException; import java.util.Arrays; import static junit.framework.TestCase.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; /** * Created by matsjerratsch on 12/11/15. */ public class LNEstablishHandlerTest { EmbeddedChannel channel1; EmbeddedChannel channel2; NodeServer nodeServer1 = new NodeServer(); NodeServer nodeServer2 = new NodeServer(); NodeClient node1 = new NodeClient(nodeServer2); NodeClient node2 = new NodeClient(nodeServer1); ContextFactory contextFactory1; ContextFactory contextFactory2; LNEstablishProcessorImpl processor1; LNEstablishProcessorImpl processor2; DBHandler dbHandler1 = new InMemoryDBHandler(); DBHandler dbHandler2 = new InMemoryDBHandler(); MockBlockchainHelper mockBlockchainHelper = new MockBlockchainHelper(); MockBroadcastHelper broadcastHelper = new MockBroadcastHelper(); @Before public void prepare () throws PropertyVetoException, SQLException { node1.isServer = false; node1.intent = ChannelIntent.OPEN_CHANNEL; node2.isServer = true; contextFactory1 = new EstablishMockContextFactory(nodeServer1, dbHandler1); contextFactory2 = new EstablishMockContextFactory(nodeServer2, dbHandler2); processor1 = new LNEstablishProcessorImpl(contextFactory1, dbHandler1, node1); processor2 = new LNEstablishProcessorImpl(contextFactory2, dbHandler2, node2); channel1 = new EmbeddedChannel(new ProcessorHandler(processor1, "LNEstablish1")); channel2 = new EmbeddedChannel(new ProcessorHandler(processor2, "LNEstablish2")); Message m = (Message) channel2.readOutbound(); assertNull(m); } public void after () { channel1.checkException(); channel2.checkException(); } @Test public void shouldSendMessageA () { LNEstablishAMessage message = (LNEstablishAMessage) channel1.readOutbound(); Channel channel = processor1.channel; //Should send keys, secretHash and amounts assertTrue(Arrays.equals(message.pubKeyEscape, channel.getKeyServer().getPubKey())); assertTrue(Arrays.equals(message.pubKeyFastEscape, channel.getKeyServerA().getPubKey())); assertTrue(Arrays.equals(message.secretHashFastEscape, channel.getAnchorSecretHashServer())); assertEquals(message.clientAmount, channel.getAmountClient()); assertEquals(message.serverAmount, channel.getAmountServer()); after(); } @Test public void shouldSendMessageB () { channel2.writeInbound(channel1.readOutbound()); LNEstablishBMessage message = (LNEstablishBMessage) channel2.readOutbound(); Channel channel = processor2.channel; //Should send keys, secretHash and amounts assertTrue(Arrays.equals(message.pubKeyEscape, channel.getKeyServer().getPubKey())); assertTrue(Arrays.equals(message.pubKeyFastEscape, channel.getKeyServerA().getPubKey())); assertTrue(Arrays.equals(message.secretHashFastEscape, channel.getAnchorSecretHashServer())); assertTrue(Arrays.equals(message.anchorHash, channel.getAnchorTransactionServer(contextFactory1.getWalletHelper()).getHash().getBytes())); assertEquals(message.serverAmount, channel.getAmountServer()); after(); } @Test public void shouldSendMessageC () { channel2.writeInbound(channel1.readOutbound()); channel1.writeInbound(channel2.readOutbound()); LNEstablishCMessage message = (LNEstablishCMessage) channel1.readOutbound(); Channel channel1 = processor1.channel; Channel channel2 = processor2.channel; //Should send keys, secretHash and amounts assertTrue(Arrays.equals(message.anchorHash, channel1.getAnchorTransactionServer(contextFactory2.getWalletHelper()).getHash().getBytes())); Transaction escape = channel2.getEscapeTransactionServer(); Transaction fastEscape = channel2.getFastEscapeTransactionServer(); Sha256Hash hashEscape = escape.hashForSignature(0, channel2.getScriptAnchorOutputServer(), Transaction.SigHash.ALL, false); Sha256Hash hashFastEscape = fastEscape.hashForSignature(0, channel2.getScriptAnchorOutputServer(), Transaction.SigHash.ALL, false); assertTrue(channel2.getKeyClientA().verify(hashEscape, TransactionSignature.decodeFromBitcoin(message.signatureEscape, true))); assertTrue(channel2.getKeyClientA().verify(hashFastEscape, TransactionSignature.decodeFromBitcoin(message.signatureFastEscape, true))); after(); } @Test public void shouldSendMessageD () { channel2.writeInbound(channel1.readOutbound()); channel1.writeInbound(channel2.readOutbound()); channel2.writeInbound(channel1.readOutbound()); Channel channel = processor1.channel; //Should send keys, secretHash and amounts LNEstablishDMessage message = (LNEstablishDMessage) channel2.readOutbound(); Transaction escape = channel.getEscapeTransactionServer(); Transaction fastEscape = channel.getFastEscapeTransactionServer(); Sha256Hash hashEscape = escape.hashForSignature(0, channel.getScriptAnchorOutputServer(), Transaction.SigHash.ALL, false); Sha256Hash hashFastEscape = fastEscape.hashForSignature(0, channel.getScriptAnchorOutputServer(), Transaction.SigHash.ALL, false); assertTrue(channel.getKeyClientA().verify(hashEscape, TransactionSignature.decodeFromBitcoin(message.signatureEscape, true))); assertTrue(channel.getKeyClientA().verify(hashFastEscape, TransactionSignature.decodeFromBitcoin(message.signatureFastEscape, true))); channel1.writeInbound(message); after(); } @Test public void fullExchangeShouldBroadcast () { LNEstablishAMessage aMessage = (LNEstablishAMessage) channel1.readOutbound(); channel2.writeInbound(aMessage); LNEstablishBMessage bMessage = (LNEstablishBMessage) channel2.readOutbound(); channel1.writeInbound(bMessage); LNEstablishCMessage cMessage = (LNEstablishCMessage) channel1.readOutbound(); channel2.writeInbound(cMessage); channel1.writeInbound(channel2.readOutbound()); //TODO somehow test inclusion in block as well... assertTrue(mockBlockchainHelper.broadcastedTransaction.contains(Sha256Hash.wrap(bMessage.anchorHash))); assertTrue(mockBlockchainHelper.broadcastedTransaction.contains(Sha256Hash.wrap(cMessage.anchorHash))); //TODO check all properties of the broadcasted objects.. assertTrue(broadcastHelper.broadcastedObjects.size() == 4); after(); } @Test(expected = LNEstablishException.class) public void shouldNotAcceptSignature () { channel2.writeInbound(channel1.readOutbound()); channel1.writeInbound(channel2.readOutbound()); LNEstablishCMessage message = (LNEstablishCMessage) channel1.readOutbound(); LNEstablishCMessage messageSwappedSign = new LNEstablishCMessage(message.signatureFastEscape, message.signatureEscape, message.anchorHash); channel2.writeInbound(messageSwappedSign); assertTrue(channel2.readOutbound() instanceof FailureMessage); after(); } @Test(expected = LNEstablishException.class) public void shouldNotAcceptMessageInWrongOrder () { Message c1 = (Message) channel1.readOutbound(); channel2.writeInbound(c1); Message c2 = (Message) channel2.readOutbound(); channel1.writeInbound(c2); channel2.writeInbound(c1); assertTrue(channel2.readOutbound() instanceof FailureMessage); after(); } class EstablishMockContextFactory extends ContextFactoryImpl { public EstablishMockContextFactory (NodeServer node, DBHandler dbHandler) { super(node, dbHandler, new MockWallet(Constants.getNetwork()), new MockLNEventHelper()); } @Override public BlockchainHelper getBlockchainHelper () { return mockBlockchainHelper; } @Override public BroadcastHelper getBroadcastHelper () { return broadcastHelper; } } }