use of co.rsk.bitcoinj.core.BtcBlock in project rskj by rsksmart.
the class RepositoryBtcBlockStoreWithCacheTest method getStoredBlockAtMainChainHeight_postIris_heightLowerThanMaxDepth_limitInChainHeadMinusMaxDepthToSearch.
@Test(expected = BlockStoreException.class)
public void getStoredBlockAtMainChainHeight_postIris_heightLowerThanMaxDepth_limitInChainHeadMinusMaxDepthToSearch() throws BlockStoreException {
Repository repository = createRepository();
BtcBlockStoreWithCache.Factory btcBlockStoreFactory = new RepositoryBtcBlockStoreWithCache.Factory(bridgeConstants.getBtcParams());
BridgeStorageProvider provider = mock(BridgeStorageProvider.class);
ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class);
when(activations.isActive(ConsensusRule.RSKIP199)).thenReturn(true);
BtcBlockStoreWithCache btcBlockStore = btcBlockStoreFactory.newInstance(repository, bridgeConstants, provider, activations);
BtcBlock genesis = networkParameters.getGenesisBlock();
int btcHeightWhenBlockIndexActivates = bridgeConstants.getBtcHeightWhenBlockIndexActivates();
int maxDepthToSearchBlocksBelowIndexActivation = bridgeConstants.getMaxDepthToSearchBlocksBelowIndexActivation();
int blockHeight = btcHeightWhenBlockIndexActivates + maxDepthToSearchBlocksBelowIndexActivation - 1;
StoredBlock storedBlock1 = createStoredBlock(genesis, blockHeight, 0);
btcBlockStore.put(storedBlock1);
btcBlockStore.setChainHead(storedBlock1);
assertEquals(storedBlock1, btcBlockStore.getChainHead());
// Search for a block in a height lower than the max depth, should fail
// Since the chain height is below btcHeightWhenBlockIndexActivates + maxDepthToSearchBlocksBelowIndexActivation
int maxDepth = blockHeight - maxDepthToSearchBlocksBelowIndexActivation;
btcBlockStore.getStoredBlockAtMainChainHeight(maxDepth - 1);
}
use of co.rsk.bitcoinj.core.BtcBlock in project rskj by rsksmart.
the class RepositoryBtcBlockStoreWithCacheTest method checkDifferentInstancesWithSameRepoHaveSameContentTest.
@Test
public void checkDifferentInstancesWithSameRepoHaveSameContentTest() throws Exception {
// This Is how I produced RepositoryBlockStore_data.ser. I had a bitcoind in regtest with 613 blocks + genesis block
// NetworkParameters params = RegTestParams.get();
// Context context = new Context(params);
// Wallet wallet = new Wallet(context);
// BlockStore store = new SPVBlockStore(params, new File("spvBlockstore"));
// AbstractBlockChain chain = new BlockChain(context, wallet, store);
// PeerGroup peerGroup = new PeerGroup(context, chain);
// peerGroup.start();
// final DownloadProgressTracker listener = new DownloadProgressTracker();
// peerGroup.startBlockChainDownload(listener);
// listener.await();
// peerGroup.stop();
// StoredBlock storedBlock = chain.getChainHead();
// FileOutputStream fos = new FileOutputStream("RepositoryBlockStore_data.ser");
// ObjectOutputStream oos = new ObjectOutputStream(fos);
// for (int i = 0; i < 614; i++) {
// Triple<byte[], BigInteger , Integer> tripleStoredBlock = new ImmutableTriple<>(storedBlock.getHeader().bitcoinSerialize(), storedBlock.getChainWork(), storedBlock.getHeight());
// oos.writeObject(tripleStoredBlock);
// storedBlock = store.get(storedBlock.getHeader().getPrevBlockHash());
// }
// oos.close();
// Read original store
InputStream fileInputStream = ClassLoader.getSystemResourceAsStream("peg/RepositoryBlockStore_data.ser");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
Repository repository = createRepository();
BtcBlockStoreWithCache.Factory btcBlockStoreFactory = new RepositoryBtcBlockStoreWithCache.Factory(bridgeConstants.getBtcParams());
BtcBlockStoreWithCache store = btcBlockStoreFactory.newInstance(repository, bridgeConstants, mock(BridgeStorageProvider.class), mock(ActivationConfig.ForBlock.class));
for (int i = 0; i < 614; i++) {
Triple<byte[], BigInteger, Integer> tripleStoredBlock = (Triple<byte[], BigInteger, Integer>) objectInputStream.readObject();
BtcBlock header = RegTestParams.get().getDefaultSerializer().makeBlock(tripleStoredBlock.getLeft());
StoredBlock storedBlock = new StoredBlock(header, tripleStoredBlock.getMiddle(), tripleStoredBlock.getRight());
if (i == 0) {
store.setChainHead(storedBlock);
}
store.put(storedBlock);
}
// Create a new instance of the store
BtcBlockStoreWithCache store2 = btcBlockStoreFactory.newInstance(repository, bridgeConstants, mock(BridgeStorageProvider.class), mock(ActivationConfig.ForBlock.class));
// Check a specific block that used to fail when we had a bug
assertEquals(store.get(Sha256Hash.wrap("373941fe83961cf70e181e468abc5f9f7cc440c711c3d06948fa66f3912ed27a")), store2.get(Sha256Hash.wrap("373941fe83961cf70e181e468abc5f9f7cc440c711c3d06948fa66f3912ed27a")));
// Check new instance content is identical to the original one
StoredBlock storedBlock = store.getChainHead();
StoredBlock storedBlock2 = store2.getChainHead();
int headHeight = storedBlock.getHeight();
for (int i = 0; i < headHeight; i++) {
assertNotNull(storedBlock);
assertEquals(storedBlock, storedBlock2);
Sha256Hash prevBlockHash = storedBlock.getHeader().getPrevBlockHash();
storedBlock = store.get(prevBlockHash);
storedBlock2 = store2.get(prevBlockHash);
}
}
use of co.rsk.bitcoinj.core.BtcBlock in project rskj by rsksmart.
the class RepositoryBtcBlockStoreWithCacheTest method getStoredBlockAtMainChainHeight_postIris_heightLowerThanMaxDepth_limitInBtcHeightWhenBlockIndexActivates.
@Test(expected = BlockStoreException.class)
public void getStoredBlockAtMainChainHeight_postIris_heightLowerThanMaxDepth_limitInBtcHeightWhenBlockIndexActivates() throws BlockStoreException {
Repository repository = createRepository();
BtcBlockStoreWithCache.Factory btcBlockStoreFactory = new RepositoryBtcBlockStoreWithCache.Factory(bridgeConstants.getBtcParams());
BridgeStorageProvider provider = mock(BridgeStorageProvider.class);
ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class);
when(activations.isActive(ConsensusRule.RSKIP199)).thenReturn(true);
BtcBlockStoreWithCache btcBlockStore = btcBlockStoreFactory.newInstance(repository, bridgeConstants, provider, activations);
BtcBlock genesis = networkParameters.getGenesisBlock();
int btcHeightWhenBlockIndexActivates = bridgeConstants.getBtcHeightWhenBlockIndexActivates();
int maxDepthToSearchBlocksBelowIndexActivation = bridgeConstants.getMaxDepthToSearchBlocksBelowIndexActivation();
int blockHeight = btcHeightWhenBlockIndexActivates + maxDepthToSearchBlocksBelowIndexActivation + 1;
StoredBlock storedBlock1 = createStoredBlock(genesis, blockHeight, 0);
btcBlockStore.put(storedBlock1);
btcBlockStore.setChainHead(storedBlock1);
assertEquals(storedBlock1, btcBlockStore.getChainHead());
// Search for a block in a height lower than the max depth, should fail
// Since the chain height is above btcHeightWhenBlockIndexActivates + maxDepthToSearchBlocksBelowIndexActivation
int maxDepth = btcHeightWhenBlockIndexActivates;
btcBlockStore.getStoredBlockAtMainChainHeight(maxDepth - 1);
}
use of co.rsk.bitcoinj.core.BtcBlock in project rskj by rsksmart.
the class RepositoryBtcBlockStoreWithCacheTest method getStoredBlockAtMainChainDepth_Error.
@Test
public void getStoredBlockAtMainChainDepth_Error() throws BlockStoreException {
BtcBlockStoreWithCache btcBlockStore = createBlockStore();
BtcBlock parent = networkParameters.getGenesisBlock();
BtcBlock blockHeader1 = new BtcBlock(networkParameters, 2L, parent.getHash(), Sha256Hash.ZERO_HASH, parent.getTimeSeconds() + 1, parent.getDifficultyTarget(), 0, new ArrayList<>());
StoredBlock storedBlock1 = new StoredBlock(blockHeader1, new BigInteger("0"), 2);
btcBlockStore.put(storedBlock1);
parent = blockHeader1;
BtcBlock blockHeader2 = new BtcBlock(networkParameters, 2L, parent.getHash(), Sha256Hash.ZERO_HASH, parent.getTimeSeconds() + 1, parent.getDifficultyTarget(), 0, new ArrayList<>());
StoredBlock storedBlock2 = new StoredBlock(blockHeader2, new BigInteger("0"), 2);
btcBlockStore.put(storedBlock2);
btcBlockStore.setChainHead(storedBlock2);
// getStoredBlockAtMainChainDepth should fail as the block is at a inconsistent height
try {
btcBlockStore.getStoredBlockAtMainChainDepth(1);
fail();
} catch (BlockStoreException e) {
assertTrue(true);
}
// getStoredBlockAtMainChainHeight should fail as the block is at a inconsistent height
try {
btcBlockStore.getStoredBlockAtMainChainHeight(1);
fail();
} catch (BlockStoreException e) {
assertTrue(true);
}
}
use of co.rsk.bitcoinj.core.BtcBlock 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;
}
Aggregations