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;
}
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;
}
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;
}
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);
}
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;
}
Aggregations