Skip to content

Commit

Permalink
test: refactoring state tests (#886)
Browse files Browse the repository at this point in the history
  • Loading branch information
b00f authored Dec 31, 2023
1 parent a5cc211 commit 5348228
Show file tree
Hide file tree
Showing 11 changed files with 561 additions and 794 deletions.
2 changes: 1 addition & 1 deletion consensus/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ func (cs *consensus) SetProposal(p *proposal.Proposal) {
return
}

if err := cs.bcState.ValidateBlock(p.Block()); err != nil {
if err := cs.bcState.ValidateBlock(p.Block(), p.Round()); err != nil {
cs.logger.Warn("invalid block", "proposal", p, "error", err)
return
}
Expand Down
2 changes: 1 addition & 1 deletion consensus/propose.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (s *proposeState) createProposal(height uint32, round int16) {
s.logger.Error("unable to propose a block!", "error", err)
return
}
if err := s.bcState.ValidateBlock(block); err != nil {
if err := s.bcState.ValidateBlock(block, round); err != nil {
s.logger.Error("proposed block is invalid!", "error", err)
return
}
Expand Down
144 changes: 70 additions & 74 deletions state/execution_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,136 +13,132 @@ import (
func TestProposeBlock(t *testing.T) {
td := setup(t)

curHeight := uint32(7)
for i := uint32(0); i < curHeight; i++ {
td.moveToNextHeightForAllStates(t)
}
b1, c1 := td.makeBlockAndCertificate(t, 0, td.valKey1, td.valKey2, td.valKey3)
assert.NoError(t, td.state1.CommitBlock(b1, c1))
assert.NoError(t, td.state2.CommitBlock(b1, c1))
assert.Equal(t, td.state1.LastBlockHeight(), curHeight+1)

invSubsidyTx := tx.NewSubsidyTx(1, td.valKey2.Address(),
td.state1.params.BlockReward, "duplicated subsidy transaction")
proposer := td.state.Proposer(0)
lockTime := td.state.LastBlockHeight()
dupSubsidyTx := tx.NewSubsidyTx(lockTime, proposer.Address(),
td.state.params.BlockReward, "duplicated subsidy transaction")
invTransferTx, _ := td.GenerateTestTransferTx()
invBondTx, _ := td.GenerateTestBondTx()
invSortitionTx, _ := td.GenerateTestSortitionTx()

pub, _ := td.RandBLSKeyPair()
trx1 := tx.NewTransferTx(1, td.valKey1.PublicKey().AccountAddress(), td.RandAccAddress(), 1, 1000, "")
td.HelperSignTransaction(td.valKey1.PrivateKey(), trx1)

trx2 := tx.NewBondTx(2, td.valKey1.PublicKey().AccountAddress(), pub.ValidatorAddress(), pub, 1000000000, 100000, "")
td.HelperSignTransaction(td.valKey1.PrivateKey(), trx2)

assert.NoError(t, td.state1.txPool.AppendTx(invTransferTx))
assert.NoError(t, td.state1.txPool.AppendTx(invBondTx))
assert.NoError(t, td.state1.txPool.AppendTx(invSortitionTx))
assert.NoError(t, td.state1.txPool.AppendTx(invSubsidyTx))
assert.NoError(t, td.state1.txPool.AppendTx(trx1))
assert.NoError(t, td.state1.txPool.AppendTx(trx2))

b2, c2 := td.makeBlockAndCertificate(t, 0, td.valKey1, td.valKey2, td.valKey3)
assert.Equal(t, b2.Header().PrevBlockHash(), b1.Hash())
assert.Equal(t, b2.Transactions()[1:], block.Txs{trx1, trx2})
assert.True(t, b2.Transactions()[0].IsSubsidyTx())
assert.NoError(t, td.state1.CommitBlock(b2, c2))

assert.Equal(t, td.state1.TotalPower(), int64(1000000004))
assert.Equal(t, td.state1.committee.TotalPower(), int64(4))
validTrx1 := tx.NewTransferTx(lockTime, td.genAccKey.PublicKeyNative().AccountAddress(),
td.RandAccAddress(), 1, 1000, "")
td.HelperSignTransaction(td.genAccKey, validTrx1)

validTrx2 := tx.NewBondTx(lockTime, td.genAccKey.PublicKeyNative().AccountAddress(),
pub.ValidatorAddress(), pub, 1000000000, 100000, "")
td.HelperSignTransaction(td.genAccKey, validTrx2)

assert.NoError(t, td.state.AddPendingTx(invTransferTx))
assert.NoError(t, td.state.AddPendingTx(invBondTx))
assert.NoError(t, td.state.AddPendingTx(invSortitionTx))
assert.NoError(t, td.state.AddPendingTx(dupSubsidyTx))
assert.NoError(t, td.state.AddPendingTx(validTrx1))
assert.NoError(t, td.state.AddPendingTx(validTrx2))

blk, cert := td.makeBlockAndCertificate(t, 0)
assert.Equal(t, blk.Header().PrevBlockHash(), td.state.LastBlockHash())
assert.Equal(t, blk.Transactions()[1:], block.Txs{validTrx1, validTrx2})
assert.True(t, blk.Transactions()[0].IsSubsidyTx())
assert.NoError(t, td.state.CommitBlock(blk, cert))

assert.Equal(t, td.state.TotalPower(), int64(1000000004))
assert.Equal(t, td.state.committee.TotalPower(), int64(4))
}

func TestExecuteBlock(t *testing.T) {
td := setup(t)

b1, c1 := td.makeBlockAndCertificate(t, 0, td.valKey1, td.valKey2, td.valKey3)
assert.NoError(t, td.state1.CommitBlock(b1, c1))
blk, cert := td.makeBlockAndCertificate(t, 0)
assert.NoError(t, td.state.CommitBlock(blk, cert))

proposerAddr := td.RandAccAddress()
rewardAddr := td.RandAccAddress()
invSubsidyTx := td.state1.createSubsidyTx(rewardAddr, 1001)
validSubsidyTx := td.state1.createSubsidyTx(rewardAddr, 1000)
invSubsidyTx := td.state.createSubsidyTx(rewardAddr, 1001)
validSubsidyTx := td.state.createSubsidyTx(rewardAddr, 1000)
invTransferTx, _ := td.GenerateTestTransferTx()

validTx1 := tx.NewTransferTx(1, td.valKey1.PublicKey().AccountAddress(), td.RandAccAddress(), 1, 1000, "")
td.HelperSignTransaction(td.valKey1.PrivateKey(), validTx1)
validTx1 := tx.NewTransferTx(1, td.genAccKey.PublicKeyNative().AccountAddress(),
td.RandAccAddress(), 1, 1000, "")
td.HelperSignTransaction(td.genAccKey, validTx1)

assert.NoError(t, td.state1.txPool.AppendTx(invTransferTx))
assert.NoError(t, td.state1.txPool.AppendTx(validSubsidyTx))
assert.NoError(t, td.state1.txPool.AppendTx(invSubsidyTx))
assert.NoError(t, td.state1.txPool.AppendTx(validTx1))
assert.NoError(t, td.state.AddPendingTx(invTransferTx))
assert.NoError(t, td.state.AddPendingTx(validSubsidyTx))
assert.NoError(t, td.state.AddPendingTx(invSubsidyTx))
assert.NoError(t, td.state.AddPendingTx(validTx1))

t.Run("Subsidy tx is invalid", func(t *testing.T) {
txs := block.NewTxs()
txs.Append(invSubsidyTx)
invBlock := block.MakeBlock(1, util.Now(), txs, td.state1.lastInfo.BlockHash(),
td.state1.stateRoot(), td.state1.lastInfo.Certificate(),
td.state1.lastInfo.SortitionSeed(), proposerAddr)
sb := td.state1.concreteSandbox()
invBlock := block.MakeBlock(1, util.Now(), txs, td.state.lastInfo.BlockHash(),
td.state.stateRoot(), td.state.lastInfo.Certificate(),
td.state.lastInfo.SortitionSeed(), proposerAddr)
sb := td.state.concreteSandbox()

assert.Error(t, td.state1.executeBlock(invBlock, sb))
assert.Error(t, td.state.executeBlock(invBlock, sb))
})

t.Run("Has invalid tx", func(t *testing.T) {
txs := block.NewTxs()
txs.Append(validSubsidyTx)
txs.Append(invTransferTx)
invBlock := block.MakeBlock(1, util.Now(), txs, td.state1.lastInfo.BlockHash(),
td.state1.stateRoot(), td.state1.lastInfo.Certificate(),
td.state1.lastInfo.SortitionSeed(), proposerAddr)
sb := td.state1.concreteSandbox()
invBlock := block.MakeBlock(1, util.Now(), txs, td.state.lastInfo.BlockHash(),
td.state.stateRoot(), td.state.lastInfo.Certificate(),
td.state.lastInfo.SortitionSeed(), proposerAddr)
sb := td.state.concreteSandbox()

assert.Error(t, td.state1.executeBlock(invBlock, sb))
assert.Error(t, td.state.executeBlock(invBlock, sb))
})

t.Run("Subsidy is not first tx", func(t *testing.T) {
txs := block.NewTxs()
txs.Append(validTx1)
txs.Append(validSubsidyTx)
invBlock := block.MakeBlock(1, util.Now(), txs, td.state1.lastInfo.BlockHash(),
td.state1.stateRoot(), td.state1.lastInfo.Certificate(),
td.state1.lastInfo.SortitionSeed(), proposerAddr)
sb := td.state1.concreteSandbox()
invBlock := block.MakeBlock(1, util.Now(), txs, td.state.lastInfo.BlockHash(),
td.state.stateRoot(), td.state.lastInfo.Certificate(),
td.state.lastInfo.SortitionSeed(), proposerAddr)
sb := td.state.concreteSandbox()

assert.Error(t, td.state1.executeBlock(invBlock, sb))
assert.Error(t, td.state.executeBlock(invBlock, sb))
})

t.Run("Has no subsidy", func(t *testing.T) {
txs := block.NewTxs()
txs.Append(validTx1)
invBlock := block.MakeBlock(1, util.Now(), txs, td.state1.lastInfo.BlockHash(),
td.state1.stateRoot(), td.state1.lastInfo.Certificate(),
td.state1.lastInfo.SortitionSeed(), proposerAddr)
sb := td.state1.concreteSandbox()
invBlock := block.MakeBlock(1, util.Now(), txs, td.state.lastInfo.BlockHash(),
td.state.stateRoot(), td.state.lastInfo.Certificate(),
td.state.lastInfo.SortitionSeed(), proposerAddr)
sb := td.state.concreteSandbox()

assert.Error(t, td.state1.executeBlock(invBlock, sb))
assert.Error(t, td.state.executeBlock(invBlock, sb))
})

t.Run("Two subsidy transactions", func(t *testing.T) {
txs := block.NewTxs()
txs.Append(validSubsidyTx)
txs.Append(validSubsidyTx)
invBlock := block.MakeBlock(1, util.Now(), txs, td.state1.lastInfo.BlockHash(),
td.state1.stateRoot(), td.state1.lastInfo.Certificate(),
td.state1.lastInfo.SortitionSeed(), proposerAddr)
sb := td.state1.concreteSandbox()
invBlock := block.MakeBlock(1, util.Now(), txs, td.state.lastInfo.BlockHash(),
td.state.stateRoot(), td.state.lastInfo.Certificate(),
td.state.lastInfo.SortitionSeed(), proposerAddr)
sb := td.state.concreteSandbox()

assert.Error(t, td.state1.executeBlock(invBlock, sb))
assert.Error(t, td.state.executeBlock(invBlock, sb))
})

t.Run("OK", func(t *testing.T) {
txs := block.NewTxs()
txs.Append(validSubsidyTx)
txs.Append(validTx1)
invBlock := block.MakeBlock(1, util.Now(), txs, td.state1.lastInfo.BlockHash(),
td.state1.stateRoot(), td.state1.lastInfo.Certificate(),
td.state1.lastInfo.SortitionSeed(), proposerAddr)
sb := td.state1.concreteSandbox()
assert.NoError(t, td.state1.executeBlock(invBlock, sb))
invBlock := block.MakeBlock(1, util.Now(), txs, td.state.lastInfo.BlockHash(),
td.state.stateRoot(), td.state.lastInfo.Certificate(),
td.state.lastInfo.SortitionSeed(), proposerAddr)
sb := td.state.concreteSandbox()
assert.NoError(t, td.state.executeBlock(invBlock, sb))

// Check if fee is claimed
treasury := sb.Account(crypto.TreasuryAddress)
subsidy := td.state1.params.BlockReward
assert.Equal(t, treasury.Balance(), 21*1e15-(2*subsidy)) // Two blocks has committed yet
subsidy := td.state.params.BlockReward
assert.Equal(t, treasury.Balance(), 21*1e15-(12*subsidy)) // Two blocks has committed yet
})
}
2 changes: 1 addition & 1 deletion state/facade.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type Facade interface {
LastCertificate() *certificate.Certificate
UpdateLastCertificate(v *vote.Vote) error
ProposeBlock(valKey *bls.ValidatorKey, rewardAddr crypto.Address) (*block.Block, error)
ValidateBlock(blk *block.Block) error
ValidateBlock(blk *block.Block, round int16) error
CommitBlock(blk *block.Block, cert *certificate.Certificate) error
CommitteeValidators() []*validator.Validator
IsInCommittee(addr crypto.Address) bool
Expand Down
2 changes: 1 addition & 1 deletion state/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func (m *MockState) ProposeBlock(valKey *bls.ValidatorKey, _ crypto.Address) (*b
return blk, nil
}

func (m *MockState) ValidateBlock(_ *block.Block) error {
func (m *MockState) ValidateBlock(_ *block.Block, _ int16) error {
return nil
}

Expand Down
31 changes: 10 additions & 21 deletions state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,12 @@ func (st *state) tryLoadLastInfo() error {
// This check is not strictly necessary, since the genesis state is already committed.
// However, it is good to perform this check to ensure that the genesis document has not been modified.
genStateRoot := st.calculateGenesisStateRootFromGenesisDoc()
blockOneInfo, err := st.store.Block(1)
committedBlockOne, err := st.store.Block(1)
if err != nil {
return err
}

blockOne, err := blockOneInfo.ToBlock()
blockOne, err := committedBlockOne.ToBlock()
if err != nil {
return err
}
Expand Down Expand Up @@ -153,11 +153,11 @@ func (st *state) makeGenesisState(genDoc *genesis.Genesis) error {
return err
}

committeeInstance, err := committee.NewCommittee(vals, st.params.CommitteeSize, vals[0].Address())
cmt, err := committee.NewCommittee(vals, st.params.CommitteeSize, vals[0].Address())
if err != nil {
return err
}
st.committee = committeeInstance
st.committee = cmt
st.lastInfo.UpdateBlockTime(genDoc.GenesisTime())

return nil
Expand Down Expand Up @@ -346,7 +346,7 @@ func (st *state) ProposeBlock(valKey *bls.ValidatorKey, rewardAddr crypto.Addres
return nil, errors.Errorf(errors.ErrInvalidBlock, "no subsidy transaction")
}
txs.Prepend(subsidyTx)
preSeed := st.lastInfo.SortitionSeed()
prevSeed := st.lastInfo.SortitionSeed()

blk := block.MakeBlock(
st.params.BlockVersion,
Expand All @@ -355,17 +355,17 @@ func (st *state) ProposeBlock(valKey *bls.ValidatorKey, rewardAddr crypto.Addres
st.lastInfo.BlockHash(),
st.stateRoot(),
st.lastInfo.Certificate(),
preSeed.GenerateNext(valKey.PrivateKey()),
prevSeed.GenerateNext(valKey.PrivateKey()),
valKey.Address())

return blk, nil
}

func (st *state) ValidateBlock(blk *block.Block) error {
func (st *state) ValidateBlock(blk *block.Block, round int16) error {
st.lk.Lock()
defer st.lk.Unlock()

if err := st.validateBlock(blk); err != nil {
if err := st.validateBlock(blk, round); err != nil {
return err
}

Expand Down Expand Up @@ -407,23 +407,11 @@ func (st *state) CommitBlock(blk *block.Block, cert *certificate.Certificate) er
return errors.Error(errors.ErrInvalidBlock)
}

err = st.validateBlock(blk)
err = st.validateBlock(blk, cert.Round())
if err != nil {
return err
}

// Verify proposer
proposer := st.committee.Proposer(cert.Round())
if proposer.Address() != blk.Header().ProposerAddress() {
return errors.Errorf(errors.ErrInvalidBlock,
"invalid proposer, expected %s, got %s", proposer.Address(), blk.Header().ProposerAddress())
}
// Validate sortition seed
seed := blk.Header().SortitionSeed()
if !seed.Verify(proposer.PublicKey(), st.lastInfo.SortitionSeed()) {
return errors.Errorf(errors.ErrInvalidBlock, "invalid sortition seed")
}

// -----------------------------------
// Execute block
sb := st.concreteSandbox()
Expand Down Expand Up @@ -587,6 +575,7 @@ func (st *state) proposeNextBlockTime() time.Time {
st.logger.Debug("it looks the last block had delay", "delay", now.Sub(timestamp))
timestamp = util.RoundNow(st.params.BlockIntervalInSecond)
}

return timestamp
}

Expand Down
Loading

0 comments on commit 5348228

Please sign in to comment.