Search in sources :

Example 1 with RLPList

use of org.ethereum.util.RLPList in project rskj by rsksmart.

the class BridgeSerializationUtilsTest method decodeTwoMock.

private RLPList decodeTwoMock(byte[] bytes, InnerListMode mode) {
    RLPList list = decodeList(bytes);
    if (mode == InnerListMode.LAST_ELEMENT) {
        byte[] lastElementBytes = list.get(list.size() - 1).getRLPData();
        RLPList innerList = decodeList(lastElementBytes);
        list.set(list.size() - 1, innerList);
    } else if (mode == InnerListMode.STARTING_WITH_FF_RECURSIVE) {
        for (int i = 0; i < list.size(); i++) {
            byte[] elementBytes = list.get(i).getRLPData();
            if (elementBytes.length > 0 && elementBytes[0] == -1) {
                RLPList innerList = decodeTwoMock(Arrays.copyOfRange(elementBytes, 1, elementBytes.length), mode);
                list.set(i, innerList);
            }
        }
    }
    return list;
}
Also used : RLPList(org.ethereum.util.RLPList)

Example 2 with RLPList

use of org.ethereum.util.RLPList in project rskj by rsksmart.

the class BridgeSerializationUtilsTest method mock_RLP_decode2_forMapOfHashesToLong.

private void mock_RLP_decode2_forMapOfHashesToLong() {
    // Plain list with first elements being the size
    // Sizes are 1 byte long
    // e.g., for list [a,b,c] and a.size = 5, b.size = 7, c.size = 4, then:
    // 03050704[a bytes][b bytes][c bytes]
    when(RLP.decode2(any(byte[].class))).then((InvocationOnMock invocation) -> {
        RLPList result = new RLPList();
        byte[] arg = invocation.getArgumentAt(0, byte[].class);
        // Odd byte -> long from byte
        for (int i = 0; i < arg.length; i++) {
            byte[] element;
            if (i % 2 == 0) {
                element = Hex.decode(charNTimes((char) arg[i], 64));
            } else {
                element = new byte[] { arg[i] };
            }
            result.add(() -> element);
        }
        return new ArrayList<>(Arrays.asList(result));
    });
}
Also used : InvocationOnMock(org.mockito.invocation.InvocationOnMock) RLPList(org.ethereum.util.RLPList)

Example 3 with RLPList

use of org.ethereum.util.RLPList in project rskj by rsksmart.

the class BridgeSerializationUtilsTest method decodeList.

private RLPList decodeList(byte[] bytes) {
    // First byte => length of list (n)
    // Subsequent n bytes => length of each of the n elements
    // Subsequent bytes => elements
    RLPList decoded = new RLPList();
    int size = Byte.toUnsignedInt(bytes[0]);
    int offset = size + 1;
    for (int i = 1; i <= size; i++) {
        int elementSize = Byte.toUnsignedInt(bytes[i]);
        byte[] element = Arrays.copyOfRange(bytes, offset, offset + elementSize);
        decoded.add(() -> element);
        offset += elementSize;
    }
    return decoded;
}
Also used : RLPList(org.ethereum.util.RLPList)

Example 4 with RLPList

use of org.ethereum.util.RLPList in project rskj by rsksmart.

the class BridgeSupportTest method addSignatureFromValidFederator.

/**
 * Helper method to test addSignature() with a valid federatorPublicKey parameter and both valid/invalid signatures
 * @param privateKeysToSignWith keys used to sign the tx. Federator key when we want to produce a valid signature, a random key when we want to produce an invalid signature
 * @param numberOfInputsToSign There is just 1 input. 1 when testing the happy case, other values to test attacks/bugs.
 * @param signatureCanonical Signature should be canonical. true when testing the happy case, false to test attacks/bugs.
 * @param signTwice Sign again with the same key
 * @param expectedResult "InvalidParameters", "PartiallySigned" or "FullySigned"
 */
private void addSignatureFromValidFederator(List<BtcECKey> privateKeysToSignWith, int numberOfInputsToSign, boolean signatureCanonical, boolean signTwice, String expectedResult) throws Exception {
    // Federation is the genesis federation ATM
    Federation federation = bridgeConstants.getGenesisFederation();
    Repository repository = new RepositoryImpl(config);
    final Keccak256 keccak256 = PegTestUtils.createHash3();
    Repository track = repository.startTracking();
    BridgeStorageProvider provider = new BridgeStorageProvider(track, PrecompiledContracts.BRIDGE_ADDR, config.getBlockchainConfig().getCommonConstants().getBridgeConstants());
    BtcTransaction prevTx = new BtcTransaction(btcParams);
    TransactionOutput prevOut = new TransactionOutput(btcParams, prevTx, Coin.FIFTY_COINS, federation.getAddress());
    prevTx.addOutput(prevOut);
    BtcTransaction t = new BtcTransaction(btcParams);
    TransactionOutput output = new TransactionOutput(btcParams, t, Coin.COIN, new BtcECKey().toAddress(btcParams));
    t.addOutput(output);
    t.addInput(prevOut).setScriptSig(PegTestUtils.createBaseInputScriptThatSpendsFromTheFederation(federation));
    provider.getRskTxsWaitingForSignatures().put(keccak256, t);
    provider.save();
    track.commit();
    track = repository.startTracking();
    List<LogInfo> logs = new ArrayList<>();
    BridgeEventLogger eventLogger = new BridgeEventLoggerImpl(bridgeConstants, logs);
    BridgeSupport bridgeSupport = new BridgeSupport(config, track, eventLogger, contractAddress, (Block) null);
    Script inputScript = t.getInputs().get(0).getScriptSig();
    List<ScriptChunk> chunks = inputScript.getChunks();
    byte[] program = chunks.get(chunks.size() - 1).data;
    Script redeemScript = new Script(program);
    Sha256Hash sighash = t.hashForSignature(0, redeemScript, BtcTransaction.SigHash.ALL, false);
    BtcECKey.ECDSASignature sig = privateKeysToSignWith.get(0).sign(sighash);
    if (!signatureCanonical) {
        sig = new BtcECKey.ECDSASignature(sig.r, BtcECKey.CURVE.getN().subtract(sig.s));
    }
    byte[] derEncodedSig = sig.encodeToDER();
    List derEncodedSigs = new ArrayList();
    for (int i = 0; i < numberOfInputsToSign; i++) {
        derEncodedSigs.add(derEncodedSig);
    }
    bridgeSupport.addSignature(1, findPublicKeySignedBy(federation.getPublicKeys(), privateKeysToSignWith.get(0)), derEncodedSigs, keccak256.getBytes());
    if (signTwice) {
        // Create another valid signature with the same private key
        ECDSASigner signer = new ECDSASigner();
        ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(privateKeysToSignWith.get(0).getPrivKey(), BtcECKey.CURVE);
        signer.init(true, privKey);
        BigInteger[] components = signer.generateSignature(sighash.getBytes());
        BtcECKey.ECDSASignature sig2 = new BtcECKey.ECDSASignature(components[0], components[1]).toCanonicalised();
        bridgeSupport.addSignature(1, findPublicKeySignedBy(federation.getPublicKeys(), privateKeysToSignWith.get(0)), Lists.newArrayList(sig2.encodeToDER()), keccak256.getBytes());
    }
    if (privateKeysToSignWith.size() > 1) {
        BtcECKey.ECDSASignature sig2 = privateKeysToSignWith.get(1).sign(sighash);
        byte[] derEncodedSig2 = sig2.encodeToDER();
        List derEncodedSigs2 = new ArrayList();
        for (int i = 0; i < numberOfInputsToSign; i++) {
            derEncodedSigs2.add(derEncodedSig2);
        }
        bridgeSupport.addSignature(1, findPublicKeySignedBy(federation.getPublicKeys(), privateKeysToSignWith.get(1)), derEncodedSigs2, keccak256.getBytes());
    }
    bridgeSupport.save();
    track.commit();
    provider = new BridgeStorageProvider(repository, PrecompiledContracts.BRIDGE_ADDR, config.getBlockchainConfig().getCommonConstants().getBridgeConstants());
    if ("FullySigned".equals(expectedResult)) {
        Assert.assertTrue(provider.getRskTxsWaitingForSignatures().isEmpty());
        Assert.assertThat(logs, is(not(empty())));
        Assert.assertThat(logs, hasSize(3));
        LogInfo releaseTxEvent = logs.get(2);
        Assert.assertThat(releaseTxEvent.getTopics(), hasSize(1));
        Assert.assertThat(releaseTxEvent.getTopics(), hasItem(Bridge.RELEASE_BTC_TOPIC));
        BtcTransaction releaseTx = new BtcTransaction(bridgeConstants.getBtcParams(), ((RLPList) RLP.decode2(releaseTxEvent.getData()).get(0)).get(1).getRLPData());
        Script retrievedScriptSig = releaseTx.getInput(0).getScriptSig();
        Assert.assertEquals(4, retrievedScriptSig.getChunks().size());
        Assert.assertEquals(true, retrievedScriptSig.getChunks().get(1).data.length > 0);
        Assert.assertEquals(true, retrievedScriptSig.getChunks().get(2).data.length > 0);
    } else {
        Script retrievedScriptSig = provider.getRskTxsWaitingForSignatures().get(keccak256).getInput(0).getScriptSig();
        Assert.assertEquals(4, retrievedScriptSig.getChunks().size());
        // for "InvalidParameters"
        boolean expectSignatureToBePersisted = false;
        if ("PartiallySigned".equals(expectedResult)) {
            expectSignatureToBePersisted = true;
        }
        Assert.assertEquals(expectSignatureToBePersisted, retrievedScriptSig.getChunks().get(1).data.length > 0);
        Assert.assertEquals(false, retrievedScriptSig.getChunks().get(2).data.length > 0);
    }
}
Also used : RLPList(org.ethereum.util.RLPList) BridgeEventLogger(co.rsk.peg.utils.BridgeEventLogger) BridgeEventLoggerImpl(co.rsk.peg.utils.BridgeEventLoggerImpl) Script(co.rsk.bitcoinj.script.Script) LogInfo(org.ethereum.vm.LogInfo) ECDSASigner(org.spongycastle.crypto.signers.ECDSASigner) Keccak256(co.rsk.crypto.Keccak256) ScriptChunk(co.rsk.bitcoinj.script.ScriptChunk) RLPList(org.ethereum.util.RLPList) ECPrivateKeyParameters(org.spongycastle.crypto.params.ECPrivateKeyParameters) RepositoryImpl(co.rsk.db.RepositoryImpl) BigInteger(java.math.BigInteger)

Example 5 with RLPList

use of org.ethereum.util.RLPList in project rskj by rsksmart.

the class BridgeSupportTest method addSignatureCreateEventLog.

@Test
public void addSignatureCreateEventLog() throws Exception {
    // Setup
    Federation federation = bridgeConstants.getGenesisFederation();
    Repository track = new RepositoryImpl(config).startTracking();
    BridgeStorageProvider provider = new BridgeStorageProvider(track, PrecompiledContracts.BRIDGE_ADDR, bridgeConstants);
    // Build prev btc tx
    BtcTransaction prevTx = new BtcTransaction(btcParams);
    TransactionOutput prevOut = new TransactionOutput(btcParams, prevTx, Coin.FIFTY_COINS, federation.getAddress());
    prevTx.addOutput(prevOut);
    // Build btc tx to be signed
    BtcTransaction btcTx = new BtcTransaction(btcParams);
    btcTx.addInput(prevOut).setScriptSig(PegTestUtils.createBaseInputScriptThatSpendsFromTheFederation(federation));
    TransactionOutput output = new TransactionOutput(btcParams, btcTx, Coin.COIN, new BtcECKey().toAddress(btcParams));
    btcTx.addOutput(output);
    // Save btc tx to be signed
    final Keccak256 rskTxHash = PegTestUtils.createHash3();
    provider.getRskTxsWaitingForSignatures().put(rskTxHash, btcTx);
    provider.save();
    track.commit();
    // Setup BridgeSupport
    List<LogInfo> eventLogs = new ArrayList<>();
    BridgeEventLogger eventLogger = new BridgeEventLoggerImpl(bridgeConstants, eventLogs);
    BridgeSupport bridgeSupport = new BridgeSupport(config, track, eventLogger, contractAddress, null);
    // Create signed hash of Btc tx
    Script inputScript = btcTx.getInputs().get(0).getScriptSig();
    List<ScriptChunk> chunks = inputScript.getChunks();
    byte[] program = chunks.get(chunks.size() - 1).data;
    Script redeemScript = new Script(program);
    Sha256Hash sigHash = btcTx.hashForSignature(0, redeemScript, BtcTransaction.SigHash.ALL, false);
    BtcECKey privateKeyToSignWith = ((BridgeRegTestConstants) bridgeConstants).getFederatorPrivateKeys().get(0);
    BtcECKey.ECDSASignature sig = privateKeyToSignWith.sign(sigHash);
    List derEncodedSigs = Collections.singletonList(sig.encodeToDER());
    BtcECKey federatorPubKey = findPublicKeySignedBy(federation.getPublicKeys(), privateKeyToSignWith);
    bridgeSupport.addSignature(1, federatorPubKey, derEncodedSigs, rskTxHash.getBytes());
    Assert.assertEquals(1, eventLogs.size());
    // Assert address that made the log
    LogInfo result = eventLogs.get(0);
    Assert.assertArrayEquals(PrecompiledContracts.BRIDGE_ADDR.getBytes(), result.getAddress());
    // Assert log topics
    Assert.assertEquals(1, result.getTopics().size());
    Assert.assertEquals(Bridge.ADD_SIGNATURE_TOPIC, result.getTopics().get(0));
    // Assert log data
    Assert.assertNotNull(result.getData());
    List<RLPElement> rlpData = RLP.decode2(result.getData());
    Assert.assertEquals(1, rlpData.size());
    RLPList dataList = (RLPList) rlpData.get(0);
    Assert.assertEquals(3, dataList.size());
    Assert.assertArrayEquals(btcTx.getHashAsString().getBytes(), dataList.get(0).getRLPData());
    Assert.assertArrayEquals(federatorPubKey.getPubKeyHash(), dataList.get(1).getRLPData());
    Assert.assertArrayEquals(rskTxHash.getBytes(), dataList.get(2).getRLPData());
}
Also used : BridgeEventLoggerImpl(co.rsk.peg.utils.BridgeEventLoggerImpl) Script(co.rsk.bitcoinj.script.Script) LogInfo(org.ethereum.vm.LogInfo) Keccak256(co.rsk.crypto.Keccak256) ScriptChunk(co.rsk.bitcoinj.script.ScriptChunk) RLPList(org.ethereum.util.RLPList) RLPElement(org.ethereum.util.RLPElement) RepositoryImpl(co.rsk.db.RepositoryImpl) RLPList(org.ethereum.util.RLPList) BridgeEventLogger(co.rsk.peg.utils.BridgeEventLogger) PrepareForTest(org.powermock.core.classloader.annotations.PrepareForTest) Test(org.junit.Test)

Aggregations

RLPList (org.ethereum.util.RLPList)60 RLPElement (org.ethereum.util.RLPElement)19 Test (org.junit.Test)13 Keccak256 (co.rsk.crypto.Keccak256)8 RskAddress (co.rsk.core.RskAddress)7 BigInteger (java.math.BigInteger)5 RLPItem (org.ethereum.util.RLPItem)5 LogInfo (org.ethereum.vm.LogInfo)5 Script (co.rsk.bitcoinj.script.Script)3 ScriptChunk (co.rsk.bitcoinj.script.ScriptChunk)3 Coin (co.rsk.core.Coin)3 RepositoryImpl (co.rsk.db.RepositoryImpl)3 BridgeEventLogger (co.rsk.peg.utils.BridgeEventLogger)3 BridgeEventLoggerImpl (co.rsk.peg.utils.BridgeEventLoggerImpl)3 ByteArrayInputStream (java.io.ByteArrayInputStream)3 InputStream (java.io.InputStream)3 ArrayList (java.util.ArrayList)3 co.rsk.bitcoinj.core (co.rsk.bitcoinj.core)2 ByteArrayOutputStream (java.io.ByteArrayOutputStream)2 IOException (java.io.IOException)2