From daca949fdbbf2eded4d002f789709b547a477c2d Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Fri, 2 Feb 2018 00:19:28 -0600 Subject: [PATCH] blockchain: Only tickets before SVH in block sanity. This moves the check for validating that there are only ticket purchases included in blocks before stake validation height to checkBlockSanity where is more naturally belongs since it does not require access to any previous chain context. --- blockchain/validate.go | 33 ++++++++++++++++++++------------- blockchain/validate_test.go | 27 +++++++++++---------------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/blockchain/validate.go b/blockchain/validate.go index 91dbc6cb..547dab80 100644 --- a/blockchain/validate.go +++ b/blockchain/validate.go @@ -615,6 +615,26 @@ func checkBlockSanity(block *dcrutil.Block, timeSource MedianTimeSource, flags B return ruleError(ErrRevocationsMismatch, errStr) } + // A block must not contain anything other than ticket purchases prior to + // stake validation height. + // + // NOTE: This case is impossible to hit at this point at the time this + // comment was written since the votes and revocations have already been + // proven to be zero before stake validation height and the only other + // type at the current time is ticket purchases, however, if another + // stake type is ever added, consensus would break without this check. + // It's better to be safe and it's a cheap check. + if header.Height < uint32(chainParams.StakeValidationHeight) { + if int64(len(msgBlock.STransactions)) != totalTickets { + errStr := fmt.Sprintf("block contains stake "+ + "transactions other than ticket purchases before "+ + "stake validation height %d (total: %d, expected %d)", + uint32(chainParams.StakeValidationHeight), + len(msgBlock.STransactions), header.FreshStake) + return ruleError(ErrInvalidEarlyStakeTx, errStr) + } + } + // Build merkle tree and ensure the calculated merkle root matches the // entry in the block header. This also has the effect of caching all // of the transaction hashes in the block to speed up future hash @@ -1000,7 +1020,6 @@ func (b *BlockChain) checkDupTxs(txSet []*dcrutil.Tx, view *UtxoViewpoint) error // PoW it seems unlikely that it will have stake errors (because the miner is // then just wasting hash power). func (b *BlockChain) CheckBlockStakeSanity(stakeValidationHeight int64, node *blockNode, block *dcrutil.Block, parent *dcrutil.Block, chainParams *chaincfg.Params) error { - // Setup variables. stakeTransactions := block.STransactions() msgBlock := block.MsgBlock() @@ -1033,18 +1052,6 @@ func (b *BlockChain) CheckBlockStakeSanity(stakeValidationHeight int64, node *bl // Break if the stake system is otherwise disabled. if block.Height() < stakeValidationHeight { - stakeTxSum := numSStxTx - - // Check and make sure we're only including SStx in the stake - // tx tree. - if stakeTxSum != len(stakeTransactions) { - errStr := fmt.Sprintf("Error in stake consensus: the "+ - "number of stake tx in block %v was %v, "+ - "however we expected %v", block.Hash(), - stakeTxSum, len(stakeTransactions)) - return ruleError(ErrInvalidEarlyStakeTx, errStr) - } - // Check the ticket pool size. if parentStakeNode.PoolSize() != poolSize { errStr := fmt.Sprintf("Error in stake consensus: the "+ diff --git a/blockchain/validate_test.go b/blockchain/validate_test.go index cb8080fa..19b93d77 100644 --- a/blockchain/validate_test.go +++ b/blockchain/validate_test.go @@ -197,29 +197,24 @@ func TestBlockValidationRules(t *testing.T) { earlySSGen142.FromBytes(block142Bytes) ssgenTx, _ := hex.DecodeString("01000000020000000000000000000000000000000" + - "000000000000000000000000000000000ffffffff00ffffffff76dfeab65ad4ca743" + - "4d5455e824c3871ed0b23ba967de53e417d9bdd7a6e42a60000000001ffffffff030" + - "00000000000000000002a6a28c5fca7895d9e1eeb7cf05755dfb5a7aa7b80b3fa8c6" + - "8c77ea3ae0dc5cd0fab198f0000000000000000000000000000000000046a02ffffe" + - "5700bb10000000000001abb76a91442f39dc794d4c68529baf41ffbd0613c16fddef" + - "a88ac000000000000000002c5220bb10000000000000000ffffffff04deadbeef204" + - "e00000000000019000000120000006b483045022100e0e8ffe608bdc274ac5aad896" + - "5faaa1a56341896fddf6470db4ea2509c71be1302207661b453473f3ce2e7b3311ef" + - "a0097d6fdbc5217e171cca04202b40d00b39e0f012103c8cbbf90d716d4840f05aef" + - "7b0232fd0dc3276219574a4919f0b26f62e3365e3") + "000000000000000000000000000000000ffffffff00ffffffff228896eaaeba3e57d" + + "5e2b7d9e38ed1ce9918db5dd8159620f34c0f1fff860f590000000001ffffffff030" + + "0000000000000000000266a2494f455952f88b4ff019c6673f3f01541b76e700e0c8" + + "a2ab9da000000000000009f86010000000000000000000000046a02010066cf98a80" + + "000000000001abb76a914efb4777e0c06c73883d6104a49739302db8058af88ac000" + + "00000000000000221b683090000000000000000ffffffff04deadbeef4519159f000" + + "000008e6b0100160000006a47304402202cc7a2938643d2e42e4363faa948bd19bfa" + + "d7a4f46ad040c34af9cb5d71b23d20220268189f6fd7ed2a0be573293e8814daac53" + + "01a01787c8d8d346c8b681ed91d4f0121031d90b4e6394841780c7292e385d7161cc" + + "3cacc46c894cbc7b82a2fbcae12e773") mtxFromB := new(wire.MsgTx) mtxFromB.FromBytes(ssgenTx) earlySSGen142.AddSTransaction(mtxFromB) + earlySSGen142.Header.Voters++ recalculateMsgBlockMerkleRootsSize(earlySSGen142) b142test := dcrutil.NewBlock(earlySSGen142) err = blockchain.CheckWorklessBlockSanity(b142test, timeSource, params) - if err == nil { - t.Errorf("got no error for ErrInvalidEarlyStakeTx test") - } - - // Hits error here. - err = chain.CheckConnectBlock(b142test) if err == nil || err.(blockchain.RuleError).ErrorCode != blockchain.ErrInvalidEarlyStakeTx { t.Errorf("Got unexpected no error or wrong error for "+