Search in sources :

Example 6 with BridgeConstants

use of co.rsk.config.BridgeConstants in project rskj by rsksmart.

the class BridgeUtils method isFreeBridgeTx.

public static boolean isFreeBridgeTx(SystemProperties config, Transaction rskTx, long blockNumber) {
    BlockchainNetConfig blockchainConfig = config.getBlockchainConfig();
    RskAddress receiveAddress = rskTx.getReceiveAddress();
    if (receiveAddress.equals(RskAddress.nullAddress())) {
        return false;
    }
    BridgeConstants bridgeConstants = blockchainConfig.getCommonConstants().getBridgeConstants();
    // Once the original federation changes, txs are always paid.
    return PrecompiledContracts.BRIDGE_ADDR.equals(receiveAddress) && blockchainConfig.getConfigForBlock(blockNumber).areBridgeTxsFree() && rskTx.acceptTransactionSignature(config.getBlockchainConfig().getCommonConstants().getChainId()) && (isFromFederateMember(rskTx, bridgeConstants.getGenesisFederation()) || isFromFederationChangeAuthorizedSender(rskTx, bridgeConstants) || isFromLockWhitelistChangeAuthorizedSender(rskTx, bridgeConstants) || isFromFeePerKbChangeAuthorizedSender(rskTx, bridgeConstants));
}
Also used : RskAddress(co.rsk.core.RskAddress) BlockchainNetConfig(org.ethereum.config.BlockchainNetConfig) BridgeConstants(co.rsk.config.BridgeConstants)

Example 7 with BridgeConstants

use of co.rsk.config.BridgeConstants in project rskj by rsksmart.

the class BridgeSupport method registerBtcTransaction.

/**
 * In case of a lock tx: Transfers some SBTCs to the sender of the btc tx and keeps track of the new UTXOs available for spending.
 * In case of a release tx: Keeps track of the change UTXOs, now available for spending.
 * @param btcTx The bitcoin transaction
 * @param height The height of the bitcoin block that contains the tx
 * @param pmt Partial Merklee Tree that proves the tx is included in the btc block
 * @throws BlockStoreException
 * @throws IOException
 */
public void registerBtcTransaction(Transaction rskTx, BtcTransaction btcTx, int height, PartialMerkleTree pmt) throws BlockStoreException, IOException {
    Context.propagate(btcContext);
    Federation federation = getActiveFederation();
    // Check the tx was not already processed
    if (provider.getBtcTxHashesAlreadyProcessed().keySet().contains(btcTx.getHash())) {
        logger.warn("Supplied tx was already processed");
        return;
    }
    // Check the tx is in the partial merkle tree
    List<Sha256Hash> hashesInPmt = new ArrayList<>();
    Sha256Hash merkleRoot = pmt.getTxnHashAndMerkleRoot(hashesInPmt);
    if (!hashesInPmt.contains(btcTx.getHash())) {
        logger.warn("Supplied tx is not in the supplied partial merkle tree");
        panicProcessor.panic("btclock", "Supplied tx is not in the supplied partial merkle tree");
        return;
    }
    if (height < 0) {
        logger.warn("Height is " + height + " but should be greater than 0");
        panicProcessor.panic("btclock", "Height is " + height + " but should be greater than 0");
        return;
    }
    // Check there are at least N blocks on top of the supplied height
    int headHeight = btcBlockChain.getBestChainHeight();
    if ((headHeight - height + 1) < bridgeConstants.getBtc2RskMinimumAcceptableConfirmations()) {
        logger.warn("At least " + bridgeConstants.getBtc2RskMinimumAcceptableConfirmations() + " confirmations are required, but there are only " + (headHeight - height) + " confirmations");
        return;
    }
    // Check the the merkle root equals merkle root of btc block at specified height in the btc best chain
    BtcBlock blockHeader = BridgeUtils.getStoredBlockAtHeight(btcBlockStore, height).getHeader();
    if (!blockHeader.getMerkleRoot().equals(merkleRoot)) {
        logger.warn("Supplied merkle root " + merkleRoot + "does not match block's merkle root " + blockHeader.getMerkleRoot());
        panicProcessor.panic("btclock", "Supplied merkle root " + merkleRoot + "does not match block's merkle root " + blockHeader.getMerkleRoot());
        return;
    }
    // Checks the transaction contents for sanity
    btcTx.verify();
    if (btcTx.getInputs().isEmpty()) {
        logger.warn("Tx has no inputs " + btcTx);
        panicProcessor.panic("btclock", "Tx has no inputs " + btcTx);
        return;
    }
    boolean locked = true;
    // Specific code for lock/release/none txs
    if (BridgeUtils.isLockTx(btcTx, getLiveFederations(), btcContext, bridgeConstants)) {
        logger.debug("This is a lock tx {}", btcTx);
        Script scriptSig = btcTx.getInput(0).getScriptSig();
        if (scriptSig.getChunks().size() != 2) {
            logger.warn("First input does not spend a Pay-to-PubkeyHash " + btcTx.getInput(0));
            panicProcessor.panic("btclock", "First input does not spend a Pay-to-PubkeyHash " + btcTx.getInput(0));
            return;
        }
        // Compute the total amount sent. Value could have been sent both to the
        // currently active federation as well as to the currently retiring federation.
        // Add both amounts up in that case.
        Coin amountToActive = btcTx.getValueSentToMe(getActiveFederationWallet());
        Coin amountToRetiring = Coin.ZERO;
        Wallet retiringFederationWallet = getRetiringFederationWallet();
        if (retiringFederationWallet != null) {
            amountToRetiring = btcTx.getValueSentToMe(retiringFederationWallet);
        }
        Coin totalAmount = amountToActive.add(amountToRetiring);
        // Get the sender public key
        byte[] data = scriptSig.getChunks().get(1).data;
        // Tx is a lock tx, check whether the sender is whitelisted
        BtcECKey senderBtcKey = BtcECKey.fromPublicOnly(data);
        Address senderBtcAddress = new Address(btcContext.getParams(), senderBtcKey.getPubKeyHash());
        // If the address is not whitelisted, then return the funds
        // using the exact same utxos sent to us.
        // That is, build a release transaction and get it in the release transaction set.
        // Otherwise, transfer SBTC to the sender of the BTC
        // The RSK account to update is the one that matches the pubkey "spent" on the first bitcoin tx input
        LockWhitelist lockWhitelist = provider.getLockWhitelist();
        if (!lockWhitelist.isWhitelistedFor(senderBtcAddress, totalAmount, height)) {
            locked = false;
            // Build the list of UTXOs in the BTC transaction sent to either the active
            // or retiring federation
            List<UTXO> utxosToUs = btcTx.getWalletOutputs(getNoSpendWalletForLiveFederations()).stream().map(output -> new UTXO(btcTx.getHash(), output.getIndex(), output.getValue(), 0, btcTx.isCoinBase(), output.getScriptPubKey())).collect(Collectors.toList());
            // Use the list of UTXOs to build a transaction builder
            // for the return btc transaction generation
            ReleaseTransactionBuilder txBuilder = new ReleaseTransactionBuilder(btcContext.getParams(), getUTXOBasedWalletForLiveFederations(utxosToUs), senderBtcAddress, getFeePerKb());
            Optional<ReleaseTransactionBuilder.BuildResult> buildReturnResult = txBuilder.buildEmptyWalletTo(senderBtcAddress);
            if (buildReturnResult.isPresent()) {
                provider.getReleaseTransactionSet().add(buildReturnResult.get().getBtcTx(), rskExecutionBlock.getNumber());
                logger.info("whitelist money return tx build successful to {}. Tx {}. Value {}.", senderBtcAddress, rskTx, totalAmount);
            } else {
                logger.warn("whitelist money return tx build for btc tx {} error. Return was to {}. Tx {}. Value {}", btcTx.getHash(), senderBtcAddress, rskTx, totalAmount);
                panicProcessor.panic("whitelist-return-funds", String.format("whitelist money return tx build for btc tx {} error. Return was to {}. Tx {}. Value {}", btcTx.getHash(), senderBtcAddress, rskTx, totalAmount));
            }
        } else {
            org.ethereum.crypto.ECKey key = org.ethereum.crypto.ECKey.fromPublicOnly(data);
            RskAddress sender = new RskAddress(key.getAddress());
            rskRepository.transfer(PrecompiledContracts.BRIDGE_ADDR, sender, co.rsk.core.Coin.fromBitcoin(totalAmount));
            lockWhitelist.remove(senderBtcAddress);
        }
    } else if (BridgeUtils.isReleaseTx(btcTx, federation, bridgeConstants)) {
        logger.debug("This is a release tx {}", btcTx);
    // do-nothing
    // We could call removeUsedUTXOs(btcTx) here, but we decided to not do that.
    // Used utxos should had been removed when we created the release tx.
    // Invoking removeUsedUTXOs() here would make "some" sense in theses scenarios:
    // a) In testnet, devnet or local: we restart the RSK blockchain whithout changing the federation address. We don't want to have utxos that were already spent.
    // Open problem: TxA spends TxB. registerBtcTransaction() for TxB is called, it spends a utxo the bridge is not yet aware of,
    // so nothing is removed. Then registerBtcTransaction() for TxA and the "already spent" utxo is added as it was not spent.
    // When is not guaranteed to be called in the chronological order, so a Federator can inform
    // b) In prod: Federator created a tx manually or the federation was compromised and some utxos were spent. Better not try to spend them.
    // Open problem: For performance removeUsedUTXOs() just removes 1 utxo
    } else if (BridgeUtils.isMigrationTx(btcTx, getActiveFederation(), getRetiringFederation(), btcContext, bridgeConstants)) {
        logger.debug("This is a migration tx {}", btcTx);
    } else {
        logger.warn("This is not a lock, a release nor a migration tx {}", btcTx);
        panicProcessor.panic("btclock", "This is not a lock, a release nor a migration tx " + btcTx);
        return;
    }
    Sha256Hash btcTxHash = btcTx.getHash();
    // Mark tx as processed on this block
    provider.getBtcTxHashesAlreadyProcessed().put(btcTxHash, rskExecutionBlock.getNumber());
    // locked the funds.
    if (locked) {
        saveNewUTXOs(btcTx);
    }
    logger.info("BTC Tx {} processed in RSK", btcTxHash);
}
Also used : java.util(java.util) Hex(org.spongycastle.util.encoders.Hex) LoggerFactory(org.slf4j.LoggerFactory) RskAddress(co.rsk.core.RskAddress) Keccak256(co.rsk.crypto.Keccak256) Block(org.ethereum.core.Block) TransactionSignature(co.rsk.bitcoinj.crypto.TransactionSignature) Pair(org.apache.commons.lang3.tuple.Pair) BridgeConstants(co.rsk.config.BridgeConstants) co.rsk.bitcoinj.core(co.rsk.bitcoinj.core) PrecompiledContracts(org.ethereum.vm.PrecompiledContracts) BigInteger(java.math.BigInteger) Nullable(javax.annotation.Nullable) Wallet(co.rsk.bitcoinj.wallet.Wallet) BtcBlockStore(co.rsk.bitcoinj.store.BtcBlockStore) PanicProcessor(co.rsk.panic.PanicProcessor) ScriptChunk(co.rsk.bitcoinj.script.ScriptChunk) Logger(org.slf4j.Logger) IOException(java.io.IOException) Instant(java.time.Instant) Repository(org.ethereum.core.Repository) Collectors(java.util.stream.Collectors) SendRequest(co.rsk.bitcoinj.wallet.SendRequest) Program(org.ethereum.vm.program.Program) ScriptBuilder(co.rsk.bitcoinj.script.ScriptBuilder) Script(co.rsk.bitcoinj.script.Script) BlockStoreException(co.rsk.bitcoinj.store.BlockStoreException) VisibleForTesting(com.google.common.annotations.VisibleForTesting) RskSystemProperties(co.rsk.config.RskSystemProperties) BridgeEventLogger(co.rsk.peg.utils.BridgeEventLogger) Transaction(org.ethereum.core.Transaction) InputStream(java.io.InputStream) Script(co.rsk.bitcoinj.script.Script) RskAddress(co.rsk.core.RskAddress) Wallet(co.rsk.bitcoinj.wallet.Wallet) RskAddress(co.rsk.core.RskAddress)

Example 8 with BridgeConstants

use of co.rsk.config.BridgeConstants in project rskj by rsksmart.

the class BridgeStateTest method recreateFromEmptyStorageProvider.

@Test
public void recreateFromEmptyStorageProvider() throws IOException {
    RskSystemProperties config = new RskSystemProperties();
    Repository repository = new RepositoryImpl(config, new TrieStoreImpl(new HashMapDB()));
    BridgeConstants bridgeConstants = config.getBlockchainConfig().getCommonConstants().getBridgeConstants();
    BridgeStorageProvider provider = new BridgeStorageProvider(repository, PrecompiledContracts.BRIDGE_ADDR, bridgeConstants);
    BridgeState state = new BridgeState(42, provider);
    BridgeState clone = BridgeState.create(bridgeConstants, state.getEncoded());
    Assert.assertNotNull(clone);
    Assert.assertEquals(42, clone.getBtcBlockchainBestChainHeight());
    Assert.assertTrue(clone.getBtcTxHashesAlreadyProcessed().isEmpty());
    Assert.assertTrue(clone.getActiveFederationBtcUTXOs().isEmpty());
    Assert.assertTrue(clone.getRskTxsWaitingForSignatures().isEmpty());
}
Also used : TrieStoreImpl(co.rsk.trie.TrieStoreImpl) Repository(org.ethereum.core.Repository) RepositoryImpl(co.rsk.db.RepositoryImpl) HashMapDB(org.ethereum.datasource.HashMapDB) BridgeConstants(co.rsk.config.BridgeConstants) RskSystemProperties(co.rsk.config.RskSystemProperties) Test(org.junit.Test)

Example 9 with BridgeConstants

use of co.rsk.config.BridgeConstants in project rskj by rsksmart.

the class BridgeStorageProviderTest method createSaveAndRecreateInstanceWithUTXOS.

@Test
public void createSaveAndRecreateInstanceWithUTXOS() throws IOException {
    Sha256Hash hash1 = PegTestUtils.createHash();
    Sha256Hash hash2 = PegTestUtils.createHash();
    Repository repository = new RepositoryImpl(config);
    Repository track = repository.startTracking();
    BridgeConstants bridgeConstants = config.getBlockchainConfig().getCommonConstants().getBridgeConstants();
    // Federation is the genesis federation ATM
    Federation federation = bridgeConstants.getGenesisFederation();
    BridgeStorageProvider provider0 = new BridgeStorageProvider(track, PrecompiledContracts.BRIDGE_ADDR, config.getBlockchainConfig().getCommonConstants().getBridgeConstants());
    provider0.getNewFederationBtcUTXOs().add(new UTXO(hash1, 1, Coin.COIN, 0, false, ScriptBuilder.createOutputScript(federation.getAddress())));
    provider0.getNewFederationBtcUTXOs().add(new UTXO(hash2, 2, Coin.FIFTY_COINS, 0, false, ScriptBuilder.createOutputScript(federation.getAddress())));
    provider0.save();
    track.commit();
    track = repository.startTracking();
    BridgeStorageProvider provider = new BridgeStorageProvider(track, PrecompiledContracts.BRIDGE_ADDR, config.getBlockchainConfig().getCommonConstants().getBridgeConstants());
    List<UTXO> utxos = provider.getNewFederationBtcUTXOs();
    Assert.assertTrue(utxos.get(0).getHash().equals(hash1));
    Assert.assertTrue(utxos.get(1).getHash().equals(hash2));
}
Also used : Repository(org.ethereum.core.Repository) RepositoryImpl(co.rsk.db.RepositoryImpl) BridgeConstants(co.rsk.config.BridgeConstants) PrepareForTest(org.powermock.core.classloader.annotations.PrepareForTest) Test(org.junit.Test)

Example 10 with BridgeConstants

use of co.rsk.config.BridgeConstants in project rskj by rsksmart.

the class BridgeSupportTest method registerBtcTransactionTxNotLockNorReleaseTx.

@Test
public void registerBtcTransactionTxNotLockNorReleaseTx() throws BlockStoreException, AddressFormatException, IOException {
    Repository repository = new RepositoryImpl(config);
    Repository track = repository.startTracking();
    BridgeConstants bridgeConstants = config.getBlockchainConfig().getCommonConstants().getBridgeConstants();
    BtcTransaction tx = new BtcTransaction(this.btcParams);
    Address address = ScriptBuilder.createP2SHOutputScript(2, Lists.newArrayList(new BtcECKey(), new BtcECKey(), new BtcECKey())).getToAddress(bridgeConstants.getBtcParams());
    tx.addOutput(Coin.COIN, address);
    tx.addInput(PegTestUtils.createHash(), 0, ScriptBuilder.createInputScript(null, new BtcECKey()));
    Context btcContext = new Context(bridgeConstants.getBtcParams());
    BtcBlockStore btcBlockStore = new RepositoryBlockStore(config, track, PrecompiledContracts.BRIDGE_ADDR);
    BtcBlockChain btcBlockChain = new SimpleBlockChain(btcContext, btcBlockStore);
    BridgeStorageProvider provider = new BridgeStorageProvider(track, contractAddress, config.getBlockchainConfig().getCommonConstants().getBridgeConstants());
    BridgeSupport bridgeSupport = new BridgeSupport(config, track, null, config.getBlockchainConfig().getCommonConstants().getBridgeConstants(), provider, btcBlockStore, btcBlockChain);
    byte[] bits = new byte[1];
    bits[0] = 0x01;
    List<Sha256Hash> hashes = new ArrayList<>();
    hashes.add(tx.getHash());
    PartialMerkleTree pmt = new PartialMerkleTree(btcParams, bits, hashes, 1);
    List<Sha256Hash> hashlist = new ArrayList<>();
    Sha256Hash merkleRoot = pmt.getTxnHashAndMerkleRoot(hashlist);
    co.rsk.bitcoinj.core.BtcBlock block = new co.rsk.bitcoinj.core.BtcBlock(btcParams, 1, PegTestUtils.createHash(), merkleRoot, 1, 1, 1, new ArrayList<BtcTransaction>());
    btcBlockChain.add(block);
    bridgeSupport.registerBtcTransaction(mock(Transaction.class), tx, 1, pmt);
    bridgeSupport.save();
    track.commit();
    BridgeStorageProvider provider2 = new BridgeStorageProvider(repository, PrecompiledContracts.BRIDGE_ADDR, config.getBlockchainConfig().getCommonConstants().getBridgeConstants());
    Assert.assertEquals(0, provider2.getNewFederationBtcUTXOs().size());
    Assert.assertEquals(0, provider2.getReleaseRequestQueue().getEntries().size());
    Assert.assertEquals(0, provider2.getReleaseTransactionSet().getEntries().size());
    Assert.assertTrue(provider2.getRskTxsWaitingForSignatures().isEmpty());
    Assert.assertTrue(provider2.getBtcTxHashesAlreadyProcessed().isEmpty());
}
Also used : RskAddress(co.rsk.core.RskAddress) SimpleBlockChain(co.rsk.peg.simples.SimpleBlockChain) BridgeConstants(co.rsk.config.BridgeConstants) BtcBlockStore(co.rsk.bitcoinj.store.BtcBlockStore) co.rsk.bitcoinj.core(co.rsk.bitcoinj.core) org.ethereum.core(org.ethereum.core) SimpleRskTransaction(co.rsk.peg.simples.SimpleRskTransaction) RepositoryImpl(co.rsk.db.RepositoryImpl) PrepareForTest(org.powermock.core.classloader.annotations.PrepareForTest) Test(org.junit.Test)

Aggregations

BridgeConstants (co.rsk.config.BridgeConstants)19 Test (org.junit.Test)15 PrepareForTest (org.powermock.core.classloader.annotations.PrepareForTest)13 RskAddress (co.rsk.core.RskAddress)10 RepositoryImpl (co.rsk.db.RepositoryImpl)10 SimpleRskTransaction (co.rsk.peg.simples.SimpleRskTransaction)10 co.rsk.bitcoinj.core (co.rsk.bitcoinj.core)9 org.ethereum.core (org.ethereum.core)8 BtcBlockStore (co.rsk.bitcoinj.store.BtcBlockStore)7 SimpleBlockChain (co.rsk.peg.simples.SimpleBlockChain)5 BridgeEventLogger (co.rsk.peg.utils.BridgeEventLogger)3 Repository (org.ethereum.core.Repository)3 TransactionSignature (co.rsk.bitcoinj.crypto.TransactionSignature)2 Script (co.rsk.bitcoinj.script.Script)2 BlockGenerator (co.rsk.blockchain.utils.BlockGenerator)2 RskSystemProperties (co.rsk.config.RskSystemProperties)2 Block (org.ethereum.core.Block)2 RLPList (org.ethereum.util.RLPList)2 ScriptBuilder (co.rsk.bitcoinj.script.ScriptBuilder)1 ScriptChunk (co.rsk.bitcoinj.script.ScriptChunk)1