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 "+