aboutsummaryrefslogtreecommitdiffstats
path: root/core/test
diff options
context:
space:
mode:
Diffstat (limited to 'core/test')
-rw-r--r--core/test/app.go211
-rw-r--r--core/test/app_test.go238
-rw-r--r--core/test/block-revealer.go33
-rw-r--r--core/test/block-revealer_test.go35
-rw-r--r--core/test/governance.go9
-rw-r--r--core/test/network.go17
-rw-r--r--core/test/network_test.go13
7 files changed, 268 insertions, 288 deletions
diff --git a/core/test/app.go b/core/test/app.go
index 20fe80f..769683e 100644
--- a/core/test/app.go
+++ b/core/test/app.go
@@ -18,6 +18,7 @@
package test
import (
+ "bytes"
"fmt"
"sync"
"time"
@@ -34,20 +35,18 @@ var (
// ErrMismatchBlockHashSequence means the delivering sequence between two App
// instances are different.
ErrMismatchBlockHashSequence = fmt.Errorf("mismatch block hash sequence")
- // ErrMismatchConsensusTime means the consensus timestamp between two blocks
- // with the same hash from two App instances are different.
- ErrMismatchConsensusTime = fmt.Errorf("mismatch consensus time")
+ // ErrMismatchRandomness means the randomness between two blocks with the
+ // same hash from two App instances are different.
+ ErrMismatchRandomness = fmt.Errorf("mismatch randomness")
// ErrApplicationIntegrityFailed means the internal datum in a App instance
// is not integrated.
ErrApplicationIntegrityFailed = fmt.Errorf("application integrity failed")
- // ErrConsensusTimestampOutOfOrder means the later delivered block has
- // consensus timestamp older than previous block.
- ErrConsensusTimestampOutOfOrder = fmt.Errorf(
- "consensus timestamp out of order")
- // ErrConsensusHeightOutOfOrder means the later delivered block has
- // consensus height not equal to height of previous block plus one.
- ErrConsensusHeightOutOfOrder = fmt.Errorf(
- "consensus height out of order")
+ // ErrTimestampOutOfOrder means the later delivered block has timestamp
+ // older than previous block.
+ ErrTimestampOutOfOrder = fmt.Errorf("timestamp out of order")
+ // ErrHeightOutOfOrder means the later delivered block has height not equal
+ // to height of previous block plus one.
+ ErrHeightOutOfOrder = fmt.Errorf("height out of order")
// ErrDeliveredBlockNotConfirmed means some block delivered (confirmed) but
// not confirmed.
ErrDeliveredBlockNotConfirmed = fmt.Errorf("delivered block not confirmed")
@@ -65,31 +64,36 @@ var (
// ErrParentBlockNotDelivered raised when the parent block is not seen by
// this app.
ErrParentBlockNotDelivered = fmt.Errorf("parent block not delivered")
+ // ErrMismatchDeliverPosition raised when the block hash and position are
+ // mismatched when calling BlockDelivered.
+ ErrMismatchDeliverPosition = fmt.Errorf("mismatch deliver position")
+ // ErrEmptyRandomness raised when the block contains empty randomness.
+ ErrEmptyRandomness = fmt.Errorf("empty randomness")
+ // ErrInvalidHeight refers to invalid value for block height.
+ ErrInvalidHeight = fmt.Errorf("invalid height")
)
// AppDeliveredRecord caches information when this application received
// a block delivered notification.
type AppDeliveredRecord struct {
- Result types.FinalizationResult
- When time.Time
- Pos types.Position
+ Rand []byte
+ When time.Time
+ Pos types.Position
}
// App implements Application interface for testing purpose.
type App struct {
- Confirmed map[common.Hash]*types.Block
- LastConfirmedHeight uint64
- confirmedLock sync.RWMutex
- Delivered map[common.Hash]*AppDeliveredRecord
- DeliverSequence common.Hashes
- deliveredLock sync.RWMutex
- state *State
- gov *Governance
- rEvt *utils.RoundEvent
- hEvt *common.Event
- lastPendingHeightLock sync.RWMutex
- LastPendingHeight uint64
- roundToNotify uint64
+ Confirmed map[common.Hash]*types.Block
+ LastConfirmedHeight uint64
+ confirmedLock sync.RWMutex
+ Delivered map[common.Hash]*AppDeliveredRecord
+ DeliverSequence common.Hashes
+ deliveredLock sync.RWMutex
+ state *State
+ gov *Governance
+ rEvt *utils.RoundEvent
+ hEvt *common.Event
+ roundToNotify uint64
}
// NewApp constructs a TestApp instance.
@@ -129,30 +133,20 @@ func (app *App) PreparePayload(position types.Position) ([]byte, error) {
// PrepareWitness implements Application interface.
func (app *App) PrepareWitness(height uint64) (types.Witness, error) {
- pendingHeight := app.getLastPendingWitnessHeight()
- if pendingHeight < height {
- return types.Witness{}, ErrLowerPendingHeight
- }
- if pendingHeight == 0 {
+ // Although we only perform reading operations here, to make sure what we
+ // prepared unique under concurrent access to this method, writer lock is
+ // used.
+ app.deliveredLock.Lock()
+ defer app.deliveredLock.Unlock()
+ hash, lastRec := app.LastDeliveredRecordNoLock()
+ if lastRec == nil {
return types.Witness{}, nil
}
- hash := func() common.Hash {
- app.deliveredLock.RLock()
- defer app.deliveredLock.RUnlock()
- // Our witness height starts from 1.
- h := app.DeliverSequence[pendingHeight-1]
- // Double confirm if the delivered record matches the pending height.
- if app.Delivered[h].Result.Height != pendingHeight {
- app.confirmedLock.RLock()
- defer app.confirmedLock.RUnlock()
- panic(fmt.Errorf("unmatched finalization record: %s, %v, %v",
- app.Confirmed[h], pendingHeight,
- app.Delivered[h].Result.Height))
- }
- return h
- }()
+ if lastRec.Pos.Height < height {
+ return types.Witness{}, ErrLowerPendingHeight
+ }
return types.Witness{
- Height: pendingHeight,
+ Height: lastRec.Pos.Height,
Data: hash.Bytes(),
}, nil
}
@@ -160,31 +154,30 @@ func (app *App) PrepareWitness(height uint64) (types.Witness, error) {
// VerifyBlock implements Application interface.
func (app *App) VerifyBlock(block *types.Block) types.BlockVerifyStatus {
// Make sure we can handle the witness carried by this block.
- pendingHeight := app.getLastPendingWitnessHeight()
- if pendingHeight < block.Witness.Height {
+ app.deliveredLock.RLock()
+ defer app.deliveredLock.RUnlock()
+ _, rec := app.LastDeliveredRecordNoLock()
+ if rec != nil && rec.Pos.Height < block.Witness.Height {
return types.VerifyRetryLater
}
// Confirm if the consensus height matches corresponding block hash.
var h common.Hash
copy(h[:], block.Witness.Data)
- app.deliveredLock.RLock()
- defer app.deliveredLock.RUnlock()
- // This is the difference between test.App and fullnode, fullnode has the
- // genesis block at height=0, we don't. Thus our reasonable witness starts
- // from 1.
- if block.Witness.Height > 0 {
- if block.Witness.Height != app.Delivered[h].Result.Height {
+ app.confirmedLock.RLock()
+ defer app.confirmedLock.RUnlock()
+ if block.Witness.Height >= types.GenesisHeight {
+ // Make sure the hash and height are matched.
+ confirmed, exist := app.Confirmed[h]
+ if !exist || block.Witness.Height != confirmed.Position.Height {
return types.VerifyInvalidBlock
}
}
- if block.Position.Height != 0 {
+ if block.Position.Height != types.GenesisHeight {
// This check is copied from fullnode, below is quoted from coresponding
// comment:
//
// Check if target block is the next height to be verified, we can only
// verify the next block in a given chain.
- app.confirmedLock.RLock()
- defer app.confirmedLock.RUnlock()
if app.LastConfirmedHeight+1 != block.Position.Height {
return types.VerifyRetryLater
}
@@ -197,10 +190,8 @@ func (app *App) BlockConfirmed(b types.Block) {
app.confirmedLock.Lock()
defer app.confirmedLock.Unlock()
app.Confirmed[b.Hash] = &b
- if b.Position.Height != 0 {
- if app.LastConfirmedHeight+1 != b.Position.Height {
- panic(ErrConfirmedHeightNotIncreasing)
- }
+ if app.LastConfirmedHeight+1 != b.Position.Height {
+ panic(ErrConfirmedHeightNotIncreasing)
}
app.LastConfirmedHeight = b.Position.Height
}
@@ -211,34 +202,32 @@ func (app *App) ClearUndeliveredBlocks() {
defer app.deliveredLock.RUnlock()
app.confirmedLock.Lock()
defer app.confirmedLock.Unlock()
- app.LastConfirmedHeight = uint64(len(app.DeliverSequence) - 1)
+ app.LastConfirmedHeight = uint64(len(app.DeliverSequence))
}
// BlockDelivered implements Application interface.
func (app *App) BlockDelivered(blockHash common.Hash, pos types.Position,
- result types.FinalizationResult) {
+ rand []byte) {
func() {
app.deliveredLock.Lock()
defer app.deliveredLock.Unlock()
app.Delivered[blockHash] = &AppDeliveredRecord{
- Result: result,
- When: time.Now().UTC(),
- Pos: pos,
+ Rand: common.CopyBytes(rand),
+ When: time.Now().UTC(),
+ Pos: pos,
}
- app.DeliverSequence = append(app.DeliverSequence, blockHash)
- // Make sure parent block also delivered.
- if !result.ParentHash.Equal(common.Hash{}) {
- d, exists := app.Delivered[result.ParentHash]
+ if len(app.DeliverSequence) > 0 {
+ // Make sure parent block also delivered.
+ lastHash := app.DeliverSequence[len(app.DeliverSequence)-1]
+ d, exists := app.Delivered[lastHash]
if !exists {
panic(ErrParentBlockNotDelivered)
}
- if d.Result.Height+1 != result.Height {
- panic(ErrConsensusHeightOutOfOrder)
+ if d.Pos.Height+1 != pos.Height {
+ panic(ErrHeightOutOfOrder)
}
}
- app.lastPendingHeightLock.Lock()
- defer app.lastPendingHeightLock.Unlock()
- app.LastPendingHeight = result.Height
+ app.DeliverSequence = append(app.DeliverSequence, blockHash)
}()
// Apply packed state change requests in payload.
func() {
@@ -247,7 +236,13 @@ func (app *App) BlockDelivered(blockHash common.Hash, pos types.Position,
}
app.confirmedLock.RLock()
defer app.confirmedLock.RUnlock()
- b := app.Confirmed[blockHash]
+ b, exists := app.Confirmed[blockHash]
+ if !exists {
+ panic(ErrDeliveredBlockNotConfirmed)
+ }
+ if !b.Position.Equal(pos) {
+ panic(ErrMismatchDeliverPosition)
+ }
if err := app.state.Apply(b.Payload); err != nil {
if err != ErrDuplicatedChange {
panic(err)
@@ -260,7 +255,7 @@ func (app *App) BlockDelivered(blockHash common.Hash, pos types.Position,
}
}
}()
- app.hEvt.NotifyHeight(result.Height)
+ app.hEvt.NotifyHeight(pos.Height)
}
// GetLatestDeliveredPosition would return the latest position of delivered
@@ -298,9 +293,9 @@ func (app *App) Compare(other *App) (err error) {
err = ErrMismatchBlockHashSequence
return
}
- if app.Delivered[h].Result.Timestamp !=
- other.Delivered[h].Result.Timestamp {
- err = ErrMismatchConsensusTime
+ if bytes.Compare(app.Delivered[h].Rand,
+ other.Delivered[h].Rand) != 0 {
+ err = ErrMismatchRandomness
return
}
}
@@ -311,7 +306,6 @@ func (app *App) Compare(other *App) (err error) {
// Verify checks the integrity of date received by this App instance.
func (app *App) Verify() error {
- // TODO(mission): verify blocks' position when delivered.
app.confirmedLock.RLock()
defer app.confirmedLock.RUnlock()
app.deliveredLock.RLock()
@@ -326,24 +320,37 @@ func (app *App) Verify() error {
expectHeight := uint64(1)
prevTime := time.Time{}
for _, h := range app.DeliverSequence {
- _, exists := app.Confirmed[h]
- if !exists {
+ _, exist := app.Confirmed[h]
+ if !exist {
return ErrDeliveredBlockNotConfirmed
}
- rec, exists := app.Delivered[h]
- if !exists {
+ _, exist = app.Delivered[h]
+ if !exist {
+ return ErrApplicationIntegrityFailed
+ }
+ b, exist := app.Confirmed[h]
+ if !exist {
return ErrApplicationIntegrityFailed
}
// Make sure the consensus time is incremental.
- ok := prevTime.Before(rec.Result.Timestamp) ||
- prevTime.Equal(rec.Result.Timestamp)
- if !ok {
- return ErrConsensusTimestampOutOfOrder
+ if prevTime.After(b.Timestamp) {
+ return ErrTimestampOutOfOrder
}
- prevTime = rec.Result.Timestamp
+ prevTime = b.Timestamp
// Make sure the consensus height is incremental.
- if expectHeight != rec.Result.Height {
- return ErrConsensusHeightOutOfOrder
+ rec, exist := app.Delivered[h]
+ if !exist {
+ return ErrApplicationIntegrityFailed
+ }
+ if len(rec.Rand) == 0 {
+ return ErrEmptyRandomness
+ }
+ // Make sure height is valid.
+ if b.Position.Height < types.GenesisHeight {
+ return ErrInvalidHeight
+ }
+ if expectHeight != rec.Pos.Height {
+ return ErrHeightOutOfOrder
}
expectHeight++
}
@@ -362,14 +369,16 @@ func (app *App) WithLock(function func(*App)) {
defer app.confirmedLock.RUnlock()
app.deliveredLock.RLock()
defer app.deliveredLock.RUnlock()
- app.lastPendingHeightLock.RLock()
- defer app.lastPendingHeightLock.RUnlock()
function(app)
}
-func (app *App) getLastPendingWitnessHeight() uint64 {
- app.lastPendingHeightLock.RLock()
- defer app.lastPendingHeightLock.RUnlock()
- return app.LastPendingHeight
+// LastDeliveredRecordNoLock returns the latest AppDeliveredRecord under lock.
+func (app *App) LastDeliveredRecordNoLock() (common.Hash, *AppDeliveredRecord) {
+ var hash common.Hash
+ if len(app.DeliverSequence) == 0 {
+ return hash, nil
+ }
+ hash = app.DeliverSequence[len(app.DeliverSequence)-1]
+ return hash, app.Delivered[hash]
}
diff --git a/core/test/app_test.go b/core/test/app_test.go
index 0a68f5e..574604c 100644
--- a/core/test/app_test.go
+++ b/core/test/app_test.go
@@ -104,112 +104,97 @@ func (s *AppTestSuite) proposeFinalize(
}
}
-func (s *AppTestSuite) deliverBlockWithTimeFromSequenceLength(
- app *App, hash common.Hash) {
-
- s.deliverBlock(app, hash, time.Time{}.Add(
- time.Duration(len(app.DeliverSequence))*time.Second),
- uint64(len(app.DeliverSequence)+1))
-}
-
-func (s *AppTestSuite) deliverBlock(
- app *App, hash common.Hash, timestamp time.Time, height uint64) {
-
- app.BlockDelivered(hash, types.Position{}, types.FinalizationResult{
- Timestamp: timestamp,
- Height: height,
- })
-}
-
func (s *AppTestSuite) TestCompare() {
var (
- now = time.Now().UTC()
- b0 = types.Block{Hash: common.Hash{}}
- b1 = types.Block{
- Hash: common.NewRandomHash(),
- Position: types.Position{Height: 1},
+ b0 = types.Block{
+ Hash: common.Hash{},
+ Position: types.Position{Height: types.GenesisHeight},
+ Randomness: []byte("b0")}
+ b1 = types.Block{
+ Hash: common.NewRandomHash(),
+ Position: types.Position{Height: types.GenesisHeight + 1},
+ Randomness: []byte("b1"),
}
)
// Prepare an OK App instance.
app1 := NewApp(0, nil, nil)
app1.BlockConfirmed(b0)
app1.BlockConfirmed(b1)
- app1.BlockDelivered(b0.Hash, b0.Position, types.FinalizationResult{
- Height: 1,
- Timestamp: now,
- })
- app1.BlockDelivered(b1.Hash, b1.Position, types.FinalizationResult{
- Height: 2,
- Timestamp: now.Add(1 * time.Second),
- })
+ app1.BlockDelivered(b0.Hash, b0.Position, b0.Randomness)
+ app1.BlockDelivered(b1.Hash, b1.Position, b1.Randomness)
app2 := NewApp(0, nil, nil)
- s.Require().Equal(ErrEmptyDeliverSequence.Error(),
+ s.Require().EqualError(ErrEmptyDeliverSequence,
app1.Compare(app2).Error())
app2.BlockConfirmed(b0)
- app2.BlockDelivered(b0.Hash, b0.Position, types.FinalizationResult{
- Height: 1,
- Timestamp: now,
- })
+ app2.BlockDelivered(b0.Hash, b0.Position, b0.Randomness)
b1Bad := types.Block{
- Hash: common.NewRandomHash(),
- Position: types.Position{Height: 1},
+ Hash: common.NewRandomHash(),
+ Position: types.Position{Height: types.GenesisHeight + 1},
+ Randomness: []byte("b1Bad"),
}
app2.BlockConfirmed(b1Bad)
- app2.BlockDelivered(b1Bad.Hash, b1Bad.Position, types.FinalizationResult{
- Height: 1,
- Timestamp: now,
- })
- s.Require().Equal(ErrMismatchBlockHashSequence.Error(),
+ app2.BlockDelivered(b1Bad.Hash, b1Bad.Position, b1Bad.Randomness)
+ s.Require().EqualError(ErrMismatchBlockHashSequence,
app1.Compare(app2).Error())
app2 = NewApp(0, nil, nil)
app2.BlockConfirmed(b0)
- app2.BlockDelivered(b0.Hash, b0.Position, types.FinalizationResult{
- Height: 1,
- Timestamp: now.Add(1 * time.Second),
- })
- s.Require().Equal(ErrMismatchConsensusTime.Error(),
- app1.Compare(app2).Error())
+ app2.BlockDelivered(b0.Hash, b0.Position, []byte("b0-another"))
+ s.Require().EqualError(ErrMismatchRandomness, app1.Compare(app2).Error())
}
func (s *AppTestSuite) TestVerify() {
var (
now = time.Now().UTC()
- b0 = types.Block{Hash: common.Hash{}}
- b1 = types.Block{
- Hash: common.NewRandomHash(),
- Position: types.Position{Height: 1},
+ b0 = types.Block{
+ Hash: common.Hash{},
+ Position: types.Position{Height: types.GenesisHeight},
+ Randomness: []byte("b0"),
+ Timestamp: now,
+ }
+ b1 = types.Block{
+ Hash: common.NewRandomHash(),
+ Position: types.Position{Height: types.GenesisHeight + 1},
+ Randomness: []byte("b1"),
+ Timestamp: now.Add(1 * time.Second),
}
)
+ // ErrDeliveredBlockNotConfirmed
app := NewApp(0, nil, nil)
s.Require().Equal(ErrEmptyDeliverSequence.Error(), app.Verify().Error())
- app.BlockDelivered(b0.Hash, b0.Position, types.FinalizationResult{})
- app.BlockDelivered(b1.Hash, b1.Position, types.FinalizationResult{Height: 1})
- s.Require().Equal(
- ErrDeliveredBlockNotConfirmed.Error(), app.Verify().Error())
+ app.BlockDelivered(b0.Hash, b0.Position, b0.Randomness)
+ app.BlockDelivered(b1.Hash, b1.Position, b1.Randomness)
+ s.Require().EqualError(ErrDeliveredBlockNotConfirmed, app.Verify().Error())
+ // ErrTimestampOutOfOrder.
+ app = NewApp(0, nil, nil)
+ now = time.Now().UTC()
+ b0Bad := *(b0.Clone())
+ b0Bad.Timestamp = now
+ b1Bad := *(b1.Clone())
+ b1Bad.Timestamp = now.Add(-1 * time.Second)
+ app.BlockConfirmed(b0Bad)
+ app.BlockDelivered(b0Bad.Hash, b0Bad.Position, b0Bad.Randomness)
+ app.BlockConfirmed(b1Bad)
+ app.BlockDelivered(b1Bad.Hash, b1Bad.Position, b1Bad.Randomness)
+ s.Require().EqualError(ErrTimestampOutOfOrder, app.Verify().Error())
+ // ErrInvalidHeight.
+ app = NewApp(0, nil, nil)
+ b0Bad = *(b0.Clone())
+ b0Bad.Position.Height = 0
+ s.Require().Panics(func() { app.BlockConfirmed(b0Bad) })
+ b0Bad.Position.Height = 2
+ s.Require().Panics(func() { app.BlockConfirmed(b0Bad) })
+ // ErrEmptyRandomness
app = NewApp(0, nil, nil)
app.BlockConfirmed(b0)
- app.BlockDelivered(b0.Hash, b0.Position, types.FinalizationResult{
- Height: 1,
- Timestamp: now,
- })
- app.BlockConfirmed(b1)
- app.BlockDelivered(b1.Hash, b1.Position, types.FinalizationResult{
- Height: 2,
- Timestamp: now.Add(-1 * time.Second),
- })
- s.Require().Equal(ErrConsensusTimestampOutOfOrder.Error(),
- app.Verify().Error())
+ app.BlockDelivered(b0.Hash, b0.Position, []byte{})
+ s.Require().EqualError(ErrEmptyRandomness, app.Verify().Error())
+ // OK.
app = NewApp(0, nil, nil)
app.BlockConfirmed(b0)
app.BlockConfirmed(b1)
- app.BlockDelivered(b0.Hash, b0.Position, types.FinalizationResult{
- Height: 1,
- Timestamp: now,
- })
- app.BlockDelivered(b1.Hash, b1.Position, types.FinalizationResult{
- Height: 1,
- Timestamp: now.Add(1 * time.Second),
- })
+ app.BlockDelivered(b0.Hash, b0.Position, b0.Randomness)
+ app.BlockDelivered(b1.Hash, b1.Position, b1.Randomness)
+ s.Require().NoError(app.Verify())
}
func (s *AppTestSuite) TestWitness() {
@@ -217,36 +202,30 @@ func (s *AppTestSuite) TestWitness() {
app := NewApp(0, nil, nil)
deliver := func(b *types.Block) {
app.BlockConfirmed(*b)
- app.BlockDelivered(b.Hash, b.Position, b.Finalization)
+ app.BlockDelivered(b.Hash, b.Position, b.Randomness)
}
b00 := &types.Block{
- Hash: common.NewRandomHash(),
- Finalization: types.FinalizationResult{
- Height: 1,
- Timestamp: time.Now().UTC(),
- }}
+ Hash: common.NewRandomHash(),
+ Position: types.Position{Height: 1},
+ Timestamp: time.Now().UTC(),
+ Randomness: common.GenerateRandomBytes(),
+ }
b01 := &types.Block{
- Hash: common.NewRandomHash(),
- Position: types.Position{Height: 1},
- Finalization: types.FinalizationResult{
- ParentHash: b00.Hash,
- Height: 2,
- Timestamp: time.Now().UTC(),
- },
+ Hash: common.NewRandomHash(),
+ Position: types.Position{Height: 2},
+ Timestamp: time.Now().UTC(),
+ Randomness: common.GenerateRandomBytes(),
Witness: types.Witness{
- Height: 1,
+ Height: b00.Position.Height,
Data: b00.Hash.Bytes(),
}}
b02 := &types.Block{
- Hash: common.NewRandomHash(),
- Position: types.Position{Height: 2},
- Finalization: types.FinalizationResult{
- ParentHash: b01.Hash,
- Height: 3,
- Timestamp: time.Now().UTC(),
- },
+ Hash: common.NewRandomHash(),
+ Position: types.Position{Height: 3},
+ Timestamp: time.Now().UTC(),
+ Randomness: common.GenerateRandomBytes(),
Witness: types.Witness{
- Height: 1,
+ Height: b00.Position.Height,
Data: b00.Hash.Bytes(),
}}
deliver(b00)
@@ -257,24 +236,32 @@ func (s *AppTestSuite) TestWitness() {
Witness: types.Witness{Height: 4}}))
// Mismatched witness height and data, should return invalid.
s.Require().Equal(types.VerifyInvalidBlock, app.VerifyBlock(&types.Block{
- Witness: types.Witness{Height: 1, Data: b01.Hash.Bytes()}}))
+ Witness: types.Witness{
+ Height: 1,
+ Data: b01.Hash.Bytes(),
+ }}))
// We can only verify a block followed last confirmed block.
s.Require().Equal(types.VerifyRetryLater, app.VerifyBlock(&types.Block{
- Witness: types.Witness{Height: 2, Data: b01.Hash.Bytes()},
- Position: types.Position{Height: 4}}))
+ Witness: types.Witness{
+ Height: b01.Position.Height,
+ Data: b01.Hash.Bytes()},
+ Position: types.Position{Height: 5}}))
// It's the OK case.
s.Require().Equal(types.VerifyOK, app.VerifyBlock(&types.Block{
- Witness: types.Witness{Height: 2, Data: b01.Hash.Bytes()},
- Position: types.Position{Height: 3}}))
+ Witness: types.Witness{
+ Height: b01.Position.Height,
+ Data: b01.Hash.Bytes()},
+ Position: types.Position{Height: 4}}))
// Check current last pending height.
- s.Require().Equal(app.LastPendingHeight, uint64(3))
+ _, lastRec := app.LastDeliveredRecordNoLock()
+ s.Require().Equal(lastRec.Pos.Height, uint64(3))
// We can only prepare witness for what've delivered.
_, err := app.PrepareWitness(4)
s.Require().Equal(err.Error(), ErrLowerPendingHeight.Error())
// It should be ok to prepare for height that already delivered.
w, err := app.PrepareWitness(3)
s.Require().NoError(err)
- s.Require().Equal(w.Height, b02.Finalization.Height)
+ s.Require().Equal(w.Height, b02.Position.Height)
s.Require().Equal(0, bytes.Compare(w.Data, b02.Hash[:]))
}
@@ -292,10 +279,10 @@ func (s *AppTestSuite) TestAttachedWithRoundEvent() {
for r := uint64(2); r <= uint64(20); r++ {
gov.ProposeCRS(r, getCRS(r, 0))
}
- for r := uint64(0); r <= uint64(19); r++ {
- gov.NotifyRound(r, r*roundLength)
+ for r := uint64(1); r <= uint64(19); r++ {
+ gov.NotifyRound(r, utils.GetRoundHeight(gov, r-1)+roundLength)
}
- gov.NotifyRound(20, 2200)
+ gov.NotifyRound(20, 2201)
// Reset round#20 twice, then make it done DKG preparation.
gov.ResetDKG(getCRS(20, 1))
gov.ResetDKG(getCRS(20, 2))
@@ -311,8 +298,8 @@ func (s *AppTestSuite) TestAttachedWithRoundEvent() {
s.proposeMPK(gov, 22, 0, 3)
s.proposeFinalize(gov, 22, 0, 3)
// Prepare utils.RoundEvent, starts from round#19, reset(for round#20)#1.
- rEvt, err := utils.NewRoundEvent(context.Background(), gov, s.logger, 19,
- 2019, core.ConfigRoundShift)
+ rEvt, err := utils.NewRoundEvent(context.Background(), gov, s.logger,
+ types.Position{Round: 19, Height: 2019}, core.ConfigRoundShift)
s.Require().NoError(err)
// Register a handler to collects triggered events.
evts := make(chan evtParamToCheck, 3)
@@ -331,30 +318,31 @@ func (s *AppTestSuite) TestAttachedWithRoundEvent() {
deliver := func(round, start, end uint64) {
for i := start; i <= end; i++ {
b := &types.Block{
- Hash: common.NewRandomHash(),
- Position: types.Position{Round: round, Height: i},
- Finalization: types.FinalizationResult{Height: i},
+ Hash: common.NewRandomHash(),
+ Position: types.Position{Round: round, Height: i},
+ Randomness: common.GenerateRandomBytes(),
}
app.BlockConfirmed(*b)
- app.BlockDelivered(b.Hash, b.Position, b.Finalization)
+ app.BlockDelivered(b.Hash, b.Position, b.Randomness)
}
}
- // Deliver blocks from height=2020 to height=2081.
+ // Deliver blocks from height=2020 to height=2092.
for r := uint64(0); r <= uint64(19); r++ {
- deliver(r, r*roundLength, (r+1)*roundLength-1)
+ begin := utils.GetRoundHeight(gov, r)
+ deliver(r, begin, begin+roundLength-1)
}
- deliver(19, 2000, 2091)
- s.Require().Equal(<-evts, evtParamToCheck{19, 1, 2000, gov.CRS(19)})
- s.Require().Equal(<-evts, evtParamToCheck{19, 2, 2100, gov.CRS(19)})
- s.Require().Equal(<-evts, evtParamToCheck{20, 0, 2200, gov.CRS(20)})
+ deliver(19, 2001, 2092)
+ s.Require().Equal(<-evts, evtParamToCheck{19, 1, 2001, gov.CRS(19)})
+ s.Require().Equal(<-evts, evtParamToCheck{19, 2, 2101, gov.CRS(19)})
+ s.Require().Equal(<-evts, evtParamToCheck{20, 0, 2201, gov.CRS(20)})
// Deliver blocks from height=2082 to height=2281.
- deliver(19, 2092, 2199)
- deliver(20, 2200, 2291)
- s.Require().Equal(<-evts, evtParamToCheck{21, 0, 2300, gov.CRS(21)})
+ deliver(19, 2093, 2200)
+ deliver(20, 2201, 2292)
+ s.Require().Equal(<-evts, evtParamToCheck{21, 0, 2301, gov.CRS(21)})
// Deliver blocks from height=2282 to height=2381.
- deliver(20, 2292, 2299)
- deliver(21, 2300, 2391)
- s.Require().Equal(<-evts, evtParamToCheck{22, 0, 2400, gov.CRS(22)})
+ deliver(20, 2293, 2300)
+ deliver(21, 2301, 2392)
+ s.Require().Equal(<-evts, evtParamToCheck{22, 0, 2401, gov.CRS(22)})
}
func TestApp(t *testing.T) {
diff --git a/core/test/block-revealer.go b/core/test/block-revealer.go
index 7516e6c..e104f04 100644
--- a/core/test/block-revealer.go
+++ b/core/test/block-revealer.go
@@ -50,53 +50,48 @@ func loadAllBlocks(iter db.BlockIterator) (
return
}
-// CompactionChainBlockRevealer implements BlockRevealer interface, which would
+// BlockRevealerByPosition implements BlockRevealer interface, which would
// load all blocks from db, reveal them in the order of compaction chain,
// from the genesis block to the latest one.
-type CompactionChainBlockRevealer struct {
- blocks types.BlocksByFinalizationHeight
+type BlockRevealerByPosition struct {
+ blocks types.BlocksByPosition
nextRevealIndex int
}
-// NewCompactionChainBlockRevealer constructs a block revealer in the order of
+// NewBlockRevealerByPosition constructs a block revealer in the order of
// compaction chain.
-func NewCompactionChainBlockRevealer(iter db.BlockIterator,
- startHeight uint64) (r *CompactionChainBlockRevealer, err error) {
+func NewBlockRevealerByPosition(iter db.BlockIterator, startHeight uint64) (
+ r *BlockRevealerByPosition, err error) {
blocksByHash, err := loadAllBlocks(iter)
if err != nil {
return
}
- if startHeight == 0 {
- startHeight = 1
- }
- blocks := types.BlocksByFinalizationHeight{}
+ blocks := types.BlocksByPosition{}
for _, b := range blocksByHash {
- if b.Finalization.Height < startHeight {
+ if b.Position.Height < startHeight {
continue
}
blocks = append(blocks, b)
}
- sort.Sort(types.BlocksByFinalizationHeight(blocks))
- // Make sure the finalization height of blocks are incremental with step 1.
+ sort.Sort(types.BlocksByPosition(blocks))
+ // Make sure the height of blocks are incremental with step 1.
for idx, b := range blocks {
if idx == 0 {
continue
}
- if b.Finalization.Height != blocks[idx-1].Finalization.Height+1 {
+ if b.Position.Height != blocks[idx-1].Position.Height+1 {
err = ErrNotValidCompactionChain
return
}
}
- r = &CompactionChainBlockRevealer{
- blocks: blocks,
- }
+ r = &BlockRevealerByPosition{blocks: blocks}
r.Reset()
return
}
// NextBlock implements Revealer.Next method, which would reveal blocks in the
// order of compaction chain.
-func (r *CompactionChainBlockRevealer) NextBlock() (types.Block, error) {
+func (r *BlockRevealerByPosition) NextBlock() (types.Block, error) {
if r.nextRevealIndex == len(r.blocks) {
return types.Block{}, db.ErrIterationFinished
}
@@ -106,6 +101,6 @@ func (r *CompactionChainBlockRevealer) NextBlock() (types.Block, error) {
}
// Reset implement Revealer.Reset method, which would reset revealing.
-func (r *CompactionChainBlockRevealer) Reset() {
+func (r *BlockRevealerByPosition) Reset() {
r.nextRevealIndex = 0
}
diff --git a/core/test/block-revealer_test.go b/core/test/block-revealer_test.go
index 54432e8..dd2aeb8 100644
--- a/core/test/block-revealer_test.go
+++ b/core/test/block-revealer_test.go
@@ -30,34 +30,29 @@ type BlockRevealerTestSuite struct {
suite.Suite
}
-func (s *BlockRevealerTestSuite) TestCompactionChainBlockReveal() {
+func (s *BlockRevealerTestSuite) TestBlockRevealByPosition() {
dbInst, err := db.NewMemBackedDB()
s.Require().NoError(err)
- // Put several blocks with finalization field ready.
+ // Put several blocks with position field ready.
b1 := &types.Block{
- Hash: common.NewRandomHash(),
- Finalization: types.FinalizationResult{
- Height: 1,
- }}
+ Hash: common.NewRandomHash(),
+ Position: types.Position{Height: 1},
+ }
b2 := &types.Block{
- Hash: common.NewRandomHash(),
- Finalization: types.FinalizationResult{
- ParentHash: b1.Hash,
- Height: 2,
- }}
+ Hash: common.NewRandomHash(),
+ Position: types.Position{Height: 2},
+ }
b3 := &types.Block{
- Hash: common.NewRandomHash(),
- Finalization: types.FinalizationResult{
- ParentHash: b2.Hash,
- Height: 3,
- }}
+ Hash: common.NewRandomHash(),
+ Position: types.Position{Height: 3},
+ }
s.Require().NoError(dbInst.PutBlock(*b1))
s.Require().NoError(dbInst.PutBlock(*b3))
iter, err := dbInst.GetAllBlocks()
s.Require().NoError(err)
// The compaction chain is not complete, we can't construct a revealer
// instance successfully.
- r, err := NewCompactionChainBlockRevealer(iter, 0)
+ r, err := NewBlockRevealerByPosition(iter, 0)
s.Require().Nil(r)
s.Require().Equal(ErrNotValidCompactionChain.Error(), err.Error())
// Put a block to make the compaction chain complete.
@@ -65,14 +60,14 @@ func (s *BlockRevealerTestSuite) TestCompactionChainBlockReveal() {
// We can construct that revealer now.
iter, err = dbInst.GetAllBlocks()
s.Require().NoError(err)
- r, err = NewCompactionChainBlockRevealer(iter, 0)
+ r, err = NewBlockRevealerByPosition(iter, 0)
s.Require().NotNil(r)
s.Require().NoError(err)
// The revealing order should be ok.
chk := func(h uint64) {
b, err := r.NextBlock()
s.Require().NoError(err)
- s.Require().Equal(b.Finalization.Height, h)
+ s.Require().Equal(b.Position.Height, h)
}
chk(1)
chk(2)
@@ -83,7 +78,7 @@ func (s *BlockRevealerTestSuite) TestCompactionChainBlockReveal() {
// Test 'startHeight' parameter.
iter, err = dbInst.GetAllBlocks()
s.Require().NoError(err)
- r, err = NewCompactionChainBlockRevealer(iter, 2)
+ r, err = NewBlockRevealerByPosition(iter, 2)
s.Require().NotNil(r)
s.Require().NoError(err)
chk(2)
diff --git a/core/test/governance.go b/core/test/governance.go
index 4ee20d8..14b7838 100644
--- a/core/test/governance.go
+++ b/core/test/governance.go
@@ -56,7 +56,7 @@ func NewGovernance(state *State, roundShift uint64) (g *Governance, err error) {
pendingConfigChanges: make(map[uint64]map[StateChangeType]interface{}),
stateModule: state,
prohibitedTypes: make(map[StateChangeType]struct{}),
- roundBeginHeights: []uint64{0},
+ roundBeginHeights: []uint64{types.GenesisHeight},
}
return
}
@@ -94,6 +94,8 @@ func (g *Governance) Configuration(round uint64) *types.Config {
// GetRoundHeight returns the begin height of a round.
func (g *Governance) GetRoundHeight(round uint64) uint64 {
+ // This is a workaround to fit fullnode's behavior, their 0 is reserved for
+ // a genesis block unseen to core.
if round == 0 {
return 0
}
@@ -103,8 +105,7 @@ func (g *Governance) GetRoundHeight(round uint64) uint64 {
panic(fmt.Errorf("round begin height is not ready: %d %d",
round, len(g.roundBeginHeights)))
}
- // TODO(jimmy): remove this workaround.
- return g.roundBeginHeights[round] + 1
+ return g.roundBeginHeights[round]
}
// CRS returns the CRS for a given round.
@@ -342,7 +343,7 @@ func (g *Governance) CatchUpWithRound(round uint64) {
// begin height of round 0 and round 1 should be ready, they won't be
// afected by DKG reset mechanism.
g.roundBeginHeights = append(g.roundBeginHeights,
- g.configs[0].RoundLength)
+ g.configs[0].RoundLength+g.roundBeginHeights[0])
}
}
diff --git a/core/test/network.go b/core/test/network.go
index b0ce3f7..f32c27f 100644
--- a/core/test/network.go
+++ b/core/test/network.go
@@ -295,10 +295,7 @@ func (n *Network) BroadcastBlock(block *types.Block) {
}
n.addBlockToCache(block)
if block.IsFinalized() {
- n.addBlockFinalizationToCache(
- block.Hash,
- block.Finalization.Height,
- block.Finalization.Randomness)
+ n.addBlockRandomnessToCache(block.Hash, block.Randomness)
}
}
@@ -308,11 +305,7 @@ func (n *Network) BroadcastAgreementResult(
if !n.markAgreementResultAsSent(result.BlockHash) {
return
}
- n.addBlockFinalizationToCache(
- result.BlockHash,
- result.FinalizationHeight,
- result.Randomness,
- )
+ n.addBlockRandomnessToCache(result.BlockHash, result.Randomness)
notarySet := n.getNotarySet(result.Position.Round)
count := maxAgreementResultBroadcast
for nID := range notarySet {
@@ -626,16 +619,14 @@ func (n *Network) addBlockToCache(b *types.Block) {
n.blockCache[b.Hash] = b.Clone()
}
-func (n *Network) addBlockFinalizationToCache(
- hash common.Hash, height uint64, rand []byte) {
+func (n *Network) addBlockRandomnessToCache(hash common.Hash, rand []byte) {
n.blockCacheLock.Lock()
defer n.blockCacheLock.Unlock()
block, exist := n.blockCache[hash]
if !exist {
return
}
- block.Finalization.Height = height
- block.Finalization.Randomness = rand
+ block.Randomness = rand
}
func (n *Network) addVoteToCache(v *types.Vote) {
diff --git a/core/test/network_test.go b/core/test/network_test.go
index d0e9fb2..7a5ad16 100644
--- a/core/test/network_test.go
+++ b/core/test/network_test.go
@@ -252,7 +252,8 @@ func (s *NetworkTestSuite) TestBroadcastToSet() {
1, pubKeys, time.Second, &common.NullLogger{}, true), 2)
req.NoError(err)
req.NoError(gov.State().RequestChange(StateChangeNotarySetSize, uint32(1)))
- gov.NotifyRound(round, gov.Configuration(0).RoundLength)
+ gov.NotifyRound(round,
+ utils.GetRoundHeight(gov, 0)+gov.Configuration(0).RoundLength)
networks := s.setupNetworks(pubKeys)
cache := utils.NewNodeSetCache(gov)
// Cache required set of nodeIDs.
@@ -278,16 +279,16 @@ func (s *NetworkTestSuite) TestBroadcastToSet() {
req.NotNil(nerd)
req.NotNil(notaryNode)
nerd.AttachNodeSetCache(cache)
+ pos := types.Position{Round: round, Height: types.GenesisHeight}
// Try broadcasting with datum from round 0, and make sure only node belongs
// to that set receiving the message.
- nerd.BroadcastVote(&types.Vote{VoteHeader: types.VoteHeader{
- Position: types.Position{Round: round}}})
+ nerd.BroadcastVote(&types.Vote{VoteHeader: types.VoteHeader{Position: pos}})
req.IsType(&types.Vote{}, <-notaryNode.ReceiveChan())
- nerd.BroadcastDKGPrivateShare(&typesDKG.PrivateShare{Round: round})
+ nerd.BroadcastDKGPrivateShare(&typesDKG.PrivateShare{Round: pos.Round})
req.IsType(&typesDKG.PrivateShare{}, <-notaryNode.ReceiveChan())
- nerd.BroadcastDKGPartialSignature(&typesDKG.PartialSignature{Round: round})
+ nerd.BroadcastDKGPartialSignature(&typesDKG.PartialSignature{Round: pos.Round})
req.IsType(&typesDKG.PartialSignature{}, <-notaryNode.ReceiveChan())
- nerd.BroadcastBlock(&types.Block{Position: types.Position{Round: round}})
+ nerd.BroadcastBlock(&types.Block{Position: pos})
req.IsType(&types.Block{}, <-notaryNode.ReceiveChan())
}