Search in sources :

Example 31 with Sha256Hash

use of co.rsk.bitcoinj.core.Sha256Hash in project rskj by rsksmart.

the class ProofOfWorkRule method isValid.

@Override
public boolean isValid(BlockHeader header) {
    // TODO: Make ProofOfWorkRule one of the classes that inherits from AuthenticationRule.
    if (isFallbackMiningPossibleAndBlockSigned(header)) {
        boolean isValidFallbackSignature = validFallbackBlockSignature(constants, header, header.getBitcoinMergedMiningHeader());
        if (!isValidFallbackSignature) {
            logger.warn("Fallback signature failed. Header {}", header.getPrintableHash());
        }
        return isValidFallbackSignature;
    }
    co.rsk.bitcoinj.core.NetworkParameters bitcoinNetworkParameters = bridgeConstants.getBtcParams();
    MerkleProofValidator mpValidator;
    try {
        if (activationConfig.isActive(ConsensusRule.RSKIP92, header.getNumber())) {
            boolean isRskip180Enabled = activationConfig.isActive(ConsensusRule.RSKIP180, header.getNumber());
            mpValidator = new Rskip92MerkleProofValidator(header.getBitcoinMergedMiningMerkleProof(), isRskip180Enabled);
        } else {
            mpValidator = new GenesisMerkleProofValidator(bitcoinNetworkParameters, header.getBitcoinMergedMiningMerkleProof());
        }
    } catch (RuntimeException ex) {
        logger.warn("Merkle proof can't be validated. Header {}", header.getPrintableHash(), ex);
        return false;
    }
    byte[] bitcoinMergedMiningCoinbaseTransactionCompressed = header.getBitcoinMergedMiningCoinbaseTransaction();
    if (bitcoinMergedMiningCoinbaseTransactionCompressed == null) {
        logger.warn("Compressed coinbase transaction does not exist. Header {}", header.getPrintableHash());
        return false;
    }
    if (header.getBitcoinMergedMiningHeader() == null) {
        logger.warn("Bitcoin merged mining header does not exist. Header {}", header.getPrintableHash());
        return false;
    }
    BtcBlock bitcoinMergedMiningBlock = bitcoinNetworkParameters.getDefaultSerializer().makeBlock(header.getBitcoinMergedMiningHeader());
    BigInteger target = DifficultyUtils.difficultyToTarget(header.getDifficulty());
    BigInteger bitcoinMergedMiningBlockHashBI = bitcoinMergedMiningBlock.getHash().toBigInteger();
    if (bitcoinMergedMiningBlockHashBI.compareTo(target) > 0) {
        logger.warn("Hash {} is higher than target {}", bitcoinMergedMiningBlockHashBI.toString(16), target.toString(16));
        return false;
    }
    byte[] bitcoinMergedMiningCoinbaseTransactionMidstate = new byte[RskMiningConstants.MIDSTATE_SIZE];
    System.arraycopy(bitcoinMergedMiningCoinbaseTransactionCompressed, 0, bitcoinMergedMiningCoinbaseTransactionMidstate, 8, RskMiningConstants.MIDSTATE_SIZE_TRIMMED);
    byte[] bitcoinMergedMiningCoinbaseTransactionTail = new byte[bitcoinMergedMiningCoinbaseTransactionCompressed.length - RskMiningConstants.MIDSTATE_SIZE_TRIMMED];
    System.arraycopy(bitcoinMergedMiningCoinbaseTransactionCompressed, RskMiningConstants.MIDSTATE_SIZE_TRIMMED, bitcoinMergedMiningCoinbaseTransactionTail, 0, bitcoinMergedMiningCoinbaseTransactionTail.length);
    byte[] expectedCoinbaseMessageBytes = org.bouncycastle.util.Arrays.concatenate(RskMiningConstants.RSK_TAG, header.getHashForMergedMining());
    int rskTagPosition = ListArrayUtil.lastIndexOfSubList(bitcoinMergedMiningCoinbaseTransactionTail, expectedCoinbaseMessageBytes);
    if (rskTagPosition == -1) {
        logger.warn("bitcoin coinbase transaction tail message does not contain expected" + " RSKBLOCK:RskBlockHeaderHash. Expected: {} . Actual: {} .", Arrays.toString(expectedCoinbaseMessageBytes), Arrays.toString(bitcoinMergedMiningCoinbaseTransactionTail));
        return false;
    }
    /*
        * We check that the there is no other block before the rsk tag, to avoid a possible malleability attack:
        * If we have a mid state with 10 blocks, and the rsk tag, we can also have
        * another mid state with 9 blocks, 64bytes + the rsk tag, giving us two blocks with different hashes but the same spv proof.
        * */
    if (rskTagPosition >= 64) {
        logger.warn("bitcoin coinbase transaction tag position is bigger than expected 64. Actual: {}.", Integer.toString(rskTagPosition));
        return false;
    }
    int lastTag = ListArrayUtil.lastIndexOfSubList(bitcoinMergedMiningCoinbaseTransactionTail, RskMiningConstants.RSK_TAG);
    if (rskTagPosition != lastTag) {
        logger.warn("The valid RSK tag is not the last RSK tag. Tail: {}.", Arrays.toString(bitcoinMergedMiningCoinbaseTransactionTail));
        return false;
    }
    int remainingByteCount = bitcoinMergedMiningCoinbaseTransactionTail.length - rskTagPosition - RskMiningConstants.RSK_TAG.length - RskMiningConstants.BLOCK_HEADER_HASH_SIZE;
    if (remainingByteCount > RskMiningConstants.MAX_BYTES_AFTER_MERGED_MINING_HASH) {
        logger.warn("More than 128 bytes after RSK tag");
        return false;
    }
    // TODO test
    long byteCount = Pack.bigEndianToLong(bitcoinMergedMiningCoinbaseTransactionMidstate, 8);
    long coinbaseLength = bitcoinMergedMiningCoinbaseTransactionTail.length + byteCount;
    if (coinbaseLength <= 64) {
        logger.warn("Coinbase transaction must always be greater than 64-bytes long. But it was: {}", coinbaseLength);
        return false;
    }
    SHA256Digest digest = new SHA256Digest(bitcoinMergedMiningCoinbaseTransactionMidstate);
    digest.update(bitcoinMergedMiningCoinbaseTransactionTail, 0, bitcoinMergedMiningCoinbaseTransactionTail.length);
    byte[] bitcoinMergedMiningCoinbaseTransactionOneRoundOfHash = new byte[32];
    digest.doFinal(bitcoinMergedMiningCoinbaseTransactionOneRoundOfHash, 0);
    Sha256Hash bitcoinMergedMiningCoinbaseTransactionHash = Sha256Hash.wrapReversed(Sha256Hash.hash(bitcoinMergedMiningCoinbaseTransactionOneRoundOfHash));
    if (!mpValidator.isValid(bitcoinMergedMiningBlock.getMerkleRoot(), bitcoinMergedMiningCoinbaseTransactionHash)) {
        logger.warn("bitcoin merkle branch doesn't match coinbase and state root");
        return false;
    }
    return true;
}
Also used : Sha256Hash(co.rsk.bitcoinj.core.Sha256Hash) SHA256Digest(org.bouncycastle.crypto.digests.SHA256Digest) BtcBlock(co.rsk.bitcoinj.core.BtcBlock) BigInteger(java.math.BigInteger)

Example 32 with Sha256Hash

use of co.rsk.bitcoinj.core.Sha256Hash in project rskj by rsksmart.

the class BridgeUtilsTest method createPegOutTx.

private BtcTransaction createPegOutTx(List<byte[]> signatures, int inputsToAdd, Federation federation, boolean isFastBridge) {
    // Setup
    Address address;
    byte[] program;
    if (federation == null) {
        federation = BridgeRegTestConstants.getInstance().getGenesisFederation();
    }
    if (isFastBridge) {
        // Create fast bridge redeem script
        Sha256Hash derivationArgumentsHash = Sha256Hash.of(new byte[] { 1 });
        Script fastBridgeRedeemScript;
        if (federation instanceof ErpFederation) {
            fastBridgeRedeemScript = FastBridgeErpRedeemScriptParser.createFastBridgeErpRedeemScript(federation.getRedeemScript(), derivationArgumentsHash);
        } else {
            fastBridgeRedeemScript = FastBridgeRedeemScriptParser.createMultiSigFastBridgeRedeemScript(federation.getRedeemScript(), derivationArgumentsHash);
        }
        Script fastBridgeP2SH = ScriptBuilder.createP2SHOutputScript(fastBridgeRedeemScript);
        address = Address.fromP2SHHash(networkParameters, fastBridgeP2SH.getPubKeyHash());
        program = fastBridgeRedeemScript.getProgram();
    } else {
        address = federation.getAddress();
        program = federation.getRedeemScript().getProgram();
    }
    // Build prev btc tx
    BtcTransaction prevTx = new BtcTransaction(networkParameters);
    TransactionOutput prevOut = new TransactionOutput(networkParameters, prevTx, Coin.FIFTY_COINS, address);
    prevTx.addOutput(prevOut);
    // Build btc tx to be signed
    BtcTransaction btcTx = new BtcTransaction(networkParameters);
    // Add inputs
    for (int i = 0; i < inputsToAdd; i++) {
        btcTx.addInput(prevOut);
    }
    Script scriptSig;
    if (signatures.isEmpty()) {
        scriptSig = PegTestUtils.createBaseInputScriptThatSpendsFromTheFederation(federation);
    } else {
        scriptSig = ScriptBuilder.createMultiSigInputScriptBytes(signatures, program);
    }
    // Sign inputs
    for (int i = 0; i < inputsToAdd; i++) {
        btcTx.getInput(i).setScriptSig(scriptSig);
    }
    TransactionOutput output = new TransactionOutput(networkParameters, btcTx, Coin.COIN, new BtcECKey().toAddress(networkParameters));
    btcTx.addOutput(output);
    TransactionOutput changeOutput = new TransactionOutput(networkParameters, btcTx, Coin.COIN, federation.getAddress());
    btcTx.addOutput(changeOutput);
    return btcTx;
}
Also used : Script(co.rsk.bitcoinj.script.Script) TransactionOutput(co.rsk.bitcoinj.core.TransactionOutput) Address(co.rsk.bitcoinj.core.Address) RskAddress(co.rsk.core.RskAddress) Sha256Hash(co.rsk.bitcoinj.core.Sha256Hash) BtcTransaction(co.rsk.bitcoinj.core.BtcTransaction) BtcECKey(co.rsk.bitcoinj.core.BtcECKey) TransactionOutPoint(co.rsk.bitcoinj.core.TransactionOutPoint)

Example 33 with Sha256Hash

use of co.rsk.bitcoinj.core.Sha256Hash in project rskj by rsksmart.

the class BridgeSupport method validationsForRegisterBtcTransaction.

@VisibleForTesting
protected boolean validationsForRegisterBtcTransaction(Sha256Hash btcTxHash, int height, byte[] pmtSerialized, byte[] btcTxSerialized) throws BlockStoreException, VerificationException.EmptyInputsOrOutputs, BridgeIllegalArgumentException {
    // Validates height and confirmations for tx
    try {
        int acceptableConfirmationsAmount = bridgeConstants.getBtc2RskMinimumAcceptableConfirmations();
        if (!BridgeUtils.validateHeightAndConfirmations(height, getBtcBlockchainBestChainHeight(), acceptableConfirmationsAmount, btcTxHash)) {
            return false;
        }
    } catch (Exception e) {
        String panicMessage = String.format("Btc Tx %s Supplied Height is %d but should be greater than 0", btcTxHash, height);
        logger.warn(panicMessage);
        panicProcessor.panic("btclock", panicMessage);
        return false;
    }
    // Validates pmt size
    if (!PartialMerkleTreeFormatUtils.hasExpectedSize(pmtSerialized)) {
        throw new BridgeIllegalArgumentException("PartialMerkleTree doesn't have expected size");
    }
    // Calculates merkleRoot
    Sha256Hash merkleRoot;
    try {
        NetworkParameters networkParameters = bridgeConstants.getBtcParams();
        merkleRoot = BridgeUtils.calculateMerkleRoot(networkParameters, pmtSerialized, btcTxHash);
        if (merkleRoot == null) {
            return false;
        }
    } catch (VerificationException e) {
        throw new BridgeIllegalArgumentException(e.getMessage(), e);
    }
    // Validates inputs count
    logger.info("Going to validate inputs for btc tx {}", btcTxHash);
    BridgeUtils.validateInputsCount(btcTxSerialized, activations.isActive(ConsensusRule.RSKIP143));
    // Check the the merkle root equals merkle root of btc block at specified height in the btc best chain
    // BTC blockstore is available since we've already queried the best chain height
    logger.trace("Getting btc block at height: {}", height);
    BtcBlock blockHeader = btcBlockStore.getStoredBlockAtMainChainHeight(height).getHeader();
    logger.trace("Validating block merkle root at height: {}", height);
    if (!isBlockMerkleRootValid(merkleRoot, blockHeader)) {
        String panicMessage = String.format("Btc Tx %s Supplied merkle root %s does not match block's merkle root %s", btcTxHash.toString(), merkleRoot, blockHeader.getMerkleRoot());
        logger.warn(panicMessage);
        panicProcessor.panic("btclock", panicMessage);
        return false;
    }
    return true;
}
Also used : NetworkParameters(co.rsk.bitcoinj.core.NetworkParameters) Sha256Hash(co.rsk.bitcoinj.core.Sha256Hash) VerificationException(co.rsk.bitcoinj.core.VerificationException) BtcBlock(co.rsk.bitcoinj.core.BtcBlock) VMException(org.ethereum.vm.exception.VMException) UTXOProviderException(co.rsk.bitcoinj.core.UTXOProviderException) VerificationException(co.rsk.bitcoinj.core.VerificationException) InsufficientMoneyException(co.rsk.bitcoinj.core.InsufficientMoneyException) AddressFormatException(co.rsk.bitcoinj.core.AddressFormatException) IOException(java.io.IOException) BlockStoreException(co.rsk.bitcoinj.store.BlockStoreException) PeginInstructionsException(co.rsk.peg.pegininstructions.PeginInstructionsException) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Example 34 with Sha256Hash

use of co.rsk.bitcoinj.core.Sha256Hash in project rskj by rsksmart.

the class BridgeSupport method registerBtcCoinbaseTransaction.

public void registerBtcCoinbaseTransaction(byte[] btcTxSerialized, Sha256Hash blockHash, byte[] pmtSerialized, Sha256Hash witnessMerkleRoot, byte[] witnessReservedValue) throws VMException {
    Context.propagate(btcContext);
    try {
        this.ensureBtcBlockStore();
    } catch (BlockStoreException | IOException e) {
        logger.warn("Exception in registerBtcCoinbaseTransaction", e);
        throw new VMException("Exception in registerBtcCoinbaseTransaction", e);
    }
    Sha256Hash btcTxHash = BtcTransactionFormatUtils.calculateBtcTxHash(btcTxSerialized);
    if (witnessReservedValue.length != 32) {
        logger.warn("[btcTx:{}] WitnessResevedValue length can't be different than 32 bytes", btcTxHash);
        throw new BridgeIllegalArgumentException("WitnessResevedValue length can't be different than 32 bytes");
    }
    if (!PartialMerkleTreeFormatUtils.hasExpectedSize(pmtSerialized)) {
        logger.warn("[btcTx:{}] PartialMerkleTree doesn't have expected size", btcTxHash);
        throw new BridgeIllegalArgumentException("PartialMerkleTree doesn't have expected size");
    }
    Sha256Hash merkleRoot;
    try {
        PartialMerkleTree pmt = new PartialMerkleTree(bridgeConstants.getBtcParams(), pmtSerialized, 0);
        List<Sha256Hash> hashesInPmt = new ArrayList<>();
        merkleRoot = pmt.getTxnHashAndMerkleRoot(hashesInPmt);
        if (!hashesInPmt.contains(btcTxHash)) {
            logger.warn("Supplied Btc Tx {} is not in the supplied partial merkle tree", btcTxHash);
            return;
        }
    } catch (VerificationException e) {
        logger.warn("[btcTx:{}] PartialMerkleTree could not be parsed", btcTxHash);
        throw new BridgeIllegalArgumentException(String.format("PartialMerkleTree could not be parsed %s", ByteUtil.toHexString(pmtSerialized)), e);
    }
    // Check merkle root equals btc block merkle root at the specified height in the btc best chain
    // Btc blockstore is available since we've already queried the best chain height
    StoredBlock storedBlock = btcBlockStore.getFromCache(blockHash);
    if (storedBlock == null) {
        logger.warn("[btcTx:{}] Block not registered", btcTxHash);
        throw new BridgeIllegalArgumentException(String.format("Block not registered %s", blockHash.toString()));
    }
    BtcBlock blockHeader = storedBlock.getHeader();
    if (!blockHeader.getMerkleRoot().equals(merkleRoot)) {
        String panicMessage = String.format("Btc Tx %s Supplied merkle root %s does not match block's merkle root %s", btcTxHash.toString(), merkleRoot, blockHeader.getMerkleRoot());
        logger.warn(panicMessage);
        panicProcessor.panic("btclock", panicMessage);
        return;
    }
    BtcTransaction btcTx = new BtcTransaction(bridgeConstants.getBtcParams(), btcTxSerialized);
    btcTx.verify();
    Sha256Hash witnessCommitment = Sha256Hash.twiceOf(witnessMerkleRoot.getReversedBytes(), witnessReservedValue);
    if (!witnessCommitment.equals(btcTx.findWitnessCommitment())) {
        logger.warn("[btcTx:{}] WitnessCommitment does not match", btcTxHash);
        throw new BridgeIllegalArgumentException("WitnessCommitment does not match");
    }
    CoinbaseInformation coinbaseInformation = new CoinbaseInformation(witnessMerkleRoot);
    provider.setCoinbaseInformation(blockHeader.getHash(), coinbaseInformation);
    logger.warn("[btcTx:{}] Registered coinbase information", btcTxHash);
}
Also used : BlockStoreException(co.rsk.bitcoinj.store.BlockStoreException) StoredBlock(co.rsk.bitcoinj.core.StoredBlock) CoinbaseInformation(co.rsk.peg.bitcoin.CoinbaseInformation) Sha256Hash(co.rsk.bitcoinj.core.Sha256Hash) BtcTransaction(co.rsk.bitcoinj.core.BtcTransaction) ArrayList(java.util.ArrayList) IOException(java.io.IOException) VMException(org.ethereum.vm.exception.VMException) PartialMerkleTree(co.rsk.bitcoinj.core.PartialMerkleTree) VerificationException(co.rsk.bitcoinj.core.VerificationException) BtcBlock(co.rsk.bitcoinj.core.BtcBlock)

Example 35 with Sha256Hash

use of co.rsk.bitcoinj.core.Sha256Hash in project rskj by rsksmart.

the class BridgeSupport method getBtcTransactionConfirmations.

/**
 * @param btcTxHash The BTC transaction Hash
 * @param btcBlockHash The BTC block hash
 * @param merkleBranch The merkle branch
 * @throws BlockStoreException
 * @throws IOException
 */
public Integer getBtcTransactionConfirmations(Sha256Hash btcTxHash, Sha256Hash btcBlockHash, MerkleBranch merkleBranch) throws BlockStoreException, IOException {
    Context.propagate(btcContext);
    this.ensureBtcBlockChain();
    // Get the block using the given block hash
    StoredBlock block = btcBlockStore.getFromCache(btcBlockHash);
    if (block == null) {
        return BTC_TRANSACTION_CONFIRMATION_INEXISTENT_BLOCK_HASH_ERROR_CODE;
    }
    final int bestChainHeight = getBtcBlockchainBestChainHeight();
    // Prevent diving too deep in the blockchain to avoid high processing costs
    final int blockDepth = Math.max(0, bestChainHeight - block.getHeight());
    if (blockDepth > BTC_TRANSACTION_CONFIRMATION_MAX_DEPTH) {
        return BTC_TRANSACTION_CONFIRMATION_BLOCK_TOO_OLD_ERROR_CODE;
    }
    try {
        StoredBlock storedBlock = btcBlockStore.getStoredBlockAtMainChainHeight(block.getHeight());
        // Make sure it belongs to the best chain
        if (storedBlock == null || !storedBlock.equals(block)) {
            return BTC_TRANSACTION_CONFIRMATION_BLOCK_NOT_IN_BEST_CHAIN_ERROR_CODE;
        }
    } catch (BlockStoreException e) {
        logger.warn(String.format("Illegal state trying to get block with hash %s", btcBlockHash), e);
        return BTC_TRANSACTION_CONFIRMATION_INCONSISTENT_BLOCK_ERROR_CODE;
    }
    Sha256Hash merkleRoot = merkleBranch.reduceFrom(btcTxHash);
    if (!isBlockMerkleRootValid(merkleRoot, block.getHeader())) {
        return BTC_TRANSACTION_CONFIRMATION_INVALID_MERKLE_BRANCH_ERROR_CODE;
    }
    return bestChainHeight - block.getHeight() + 1;
}
Also used : StoredBlock(co.rsk.bitcoinj.core.StoredBlock) BlockStoreException(co.rsk.bitcoinj.store.BlockStoreException) Sha256Hash(co.rsk.bitcoinj.core.Sha256Hash)

Aggregations

Sha256Hash (co.rsk.bitcoinj.core.Sha256Hash)40 Test (org.junit.Test)17 StoredBlock (co.rsk.bitcoinj.core.StoredBlock)15 BtcTransaction (co.rsk.bitcoinj.core.BtcTransaction)11 BtcBlock (co.rsk.bitcoinj.core.BtcBlock)9 Script (co.rsk.bitcoinj.script.Script)7 BlockStoreException (co.rsk.bitcoinj.store.BlockStoreException)7 Repository (org.ethereum.core.Repository)7 BtcECKey (co.rsk.bitcoinj.core.BtcECKey)6 TransactionOutPoint (co.rsk.bitcoinj.core.TransactionOutPoint)6 ArrayList (java.util.ArrayList)6 ActivationConfigsForTest (org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest)6 IOException (java.io.IOException)5 PartialMerkleTree (co.rsk.bitcoinj.core.PartialMerkleTree)4 TransactionInput (co.rsk.bitcoinj.core.TransactionInput)4 TransactionSignature (co.rsk.bitcoinj.crypto.TransactionSignature)4 ScriptChunk (co.rsk.bitcoinj.script.ScriptChunk)4 BigInteger (java.math.BigInteger)4 MutableRepository (org.ethereum.db.MutableRepository)4 VerificationException (co.rsk.bitcoinj.core.VerificationException)3