new: Add wiggle to block time

This commit is contained in:
atvanguard 2020-05-14 12:19:47 +05:30 committed by Arpit Agarwal
parent 4f850edec2
commit c27b8b7801
7 changed files with 51 additions and 27 deletions

View file

@ -111,6 +111,7 @@ func (w *wizard) makeGenesis() {
Period: 1,
ProducerDelay: 5,
Sprint: 60,
BackupMultiplier: 1,
ValidatorContract: "0x0000000000000000000000000000000000001000",
StateReceiverContract: "0x0000000000000000000000000000000000001001",
}

View file

@ -207,14 +207,18 @@ func CalcDifficulty(snap *Snapshot, signer common.Address, sprint uint64) *big.I
return big.NewInt(0).SetUint64(snap.inturn(snap.Number+1, signer, sprint))
}
// CalcProducerDelay is the block delay algorithm based on block time and period / producerDelay values in genesis
func CalcProducerDelay(number uint64, period uint64, sprint uint64, producerDelay uint64) uint64 {
// CalcProducerDelay is the block delay algorithm based on block time, period, producerDelay and turn-ness of a signer
func CalcProducerDelay(number uint64, succession int, c *params.BorConfig) uint64 {
// When the block is the first block of the sprint, it is expected to be delayed by `producerDelay`.
// That is to allow time for block propagation in the last sprint
if number%sprint == 0 {
return producerDelay
delay := c.Period
if number%c.Sprint == 0 {
delay = c.ProducerDelay
}
return period
if succession > 0 {
delay += uint64(succession) * c.BackupMultiplier
}
return delay
}
// BorRLP returns the rlp bytes which needs to be signed for the bor
@ -334,17 +338,6 @@ func (c *Bor) verifyHeader(chain consensus.ChainReader, header *types.Header, pa
}
number := header.Number.Uint64()
var parent *types.Header
if len(parents) > 0 { // if parents is nil, len(parents) is zero
parent = parents[len(parents)-1]
} else if number > 0 {
parent = chain.GetHeader(header.ParentHash, number-1)
}
if parent != nil && header.Time < parent.Time+CalcProducerDelay(number, c.config.Period, c.config.Sprint, c.config.ProducerDelay) {
return consensus.ErrBlockTooSoon
}
// Don't waste time checking blocks from the future
if header.Time > uint64(time.Now().Unix()) {
return consensus.ErrFutureBlock
@ -590,10 +583,22 @@ func (c *Bor) verifySeal(chain consensus.ChainReader, header *types.Header, pare
return errUnauthorizedSigner
}
if _, err = snap.GetSignerSuccessionNumber(signer); err != nil {
succession, err := snap.GetSignerSuccessionNumber(signer)
if err != nil {
return err
}
var parent *types.Header
if len(parents) > 0 { // if parents is nil, len(parents) is zero
parent = parents[len(parents)-1]
} else if number > 0 {
parent = chain.GetHeader(header.ParentHash, number-1)
}
if parent != nil && header.Time < parent.Time+CalcProducerDelay(number, succession, c.config) {
return &BlockTooSoonError{number, succession}
}
// Ensure that the difficulty corresponds to the turn-ness of the signer
if !c.fakeDiff {
difficulty := snap.inturn(header.Number.Uint64(), signer, c.config.Sprint)
@ -654,7 +659,11 @@ func (c *Bor) Prepare(chain consensus.ChainReader, header *types.Header) error {
return consensus.ErrUnknownAncestor
}
header.Time = parent.Time + CalcProducerDelay(number, c.config.Period, c.config.Sprint, c.config.ProducerDelay)
succession, err := snap.GetSignerSuccessionNumber(c.signer)
if err != nil {
return err
}
header.Time = parent.Time + CalcProducerDelay(number, succession, c.config)
if header.Time < uint64(time.Now().Unix()) {
header.Time = uint64(time.Now().Unix())
}
@ -765,8 +774,8 @@ func (c *Bor) Seal(chain consensus.ChainReader, block *types.Block, results chan
// Sweet, the protocol permits us to sign the block, wait for our time
delay := time.Unix(int64(header.Time), 0).Sub(time.Now()) // nolint: gosimple
wiggle := time.Duration(2*c.config.Period) * time.Second * time.Duration(successionNumber)
delay += wiggle
// wiggle was already accounted for in header.Time, this is just for logging
wiggle := time.Duration(successionNumber) * time.Duration(c.config.BackupMultiplier) * time.Second
// Sign all the things!
sighash, err := signFn(accounts.Account{Address: signer}, accounts.MimetypeBor, BorRLP(header))

View file

@ -24,11 +24,7 @@ func TestCommitSpan(t *testing.T) {
// Mock HeimdallClient.FetchWithRetry to return span data from span.json
res, heimdallSpan := loadSpanFromFile(t)
h := &mocks.IHeimdallClient{}
// FetchWithRetry is invoked 3 times
// 1. bor.FinalizeAndAssemble to prepare a new block when calling insertNewBlock
// 2. bor.Finalize via(bc.insertChain => bc.processor.Process)
// 3. bor.FinalizeAndAssemble via worker.commit
h.On("FetchWithRetry", "bor", "span", "1").Return(res, nil).Times(3)
h.On("FetchWithRetry", "bor", "span", "1").Return(res, nil)
_bor.SetHeimdallClient(h)
db := init.ethereum.ChainDb()
@ -45,7 +41,10 @@ func TestCommitSpan(t *testing.T) {
block = insertNewBlock(t, _bor, chain, header, statedb, _key)
}
assert.True(t, h.AssertNumberOfCalls(t, "FetchWithRetry", 3))
// FetchWithRetry is invoked 2 times
// 1. bor.FinalizeAndAssemble to prepare a new block when calling insertNewBlock
// 2. bor.Finalize via(bc.insertChain => bc.processor.Process)
assert.True(t, h.AssertNumberOfCalls(t, "FetchWithRetry", 2))
validators, err := _bor.GetCurrentValidators(sprintSize, 256) // new span starts at 256
if err != nil {
t.Fatalf("%s", err)

View file

@ -11,6 +11,7 @@
"bor": {
"period": 1,
"producerDelay": 4,
"backupMultiplier": 1,
"sprint": 4,
"validatorContract": "0x0000000000000000000000000000000000001000",
"stateReceiverContract": "0x0000000000000000000000000000000000001001"

View file

@ -111,7 +111,7 @@ func buildMinimalNextHeader(t *testing.T, block *types.Block, borConfig *params.
header := block.Header()
header.Number.Add(header.Number, big.NewInt(1))
header.ParentHash = block.Hash()
header.Time += bor.CalcProducerDelay(header.Number.Uint64(), borConfig.Period, borConfig.Sprint, borConfig.ProducerDelay)
header.Time += bor.CalcProducerDelay(header.Number.Uint64(), 0, borConfig)
header.Extra = make([]byte, 32+65) // vanity + extraSeal
currentValidators := []*bor.Validator{bor.NewValidator(addr, 10)}

View file

@ -96,3 +96,16 @@ func (e *MismatchingValidatorsError) Error() string {
e.ValidatorSetHeader,
)
}
type BlockTooSoonError struct {
Number uint64
Succession int
}
func (e *BlockTooSoonError) Error() string {
return fmt.Sprintf(
"Block %d was created too soon. Signer turn-ness number is %d\n",
e.Number,
e.Succession,
)
}

View file

@ -319,6 +319,7 @@ type BorConfig struct {
Period uint64 `json:"period"` // Number of seconds between blocks to enforce
ProducerDelay uint64 `json:"producerDelay"` // Number of seconds delay between two producer interval
Sprint uint64 `json:"sprint"` // Epoch length to proposer
BackupMultiplier uint64 `json:"backupMultiplier"` // Backup multiplier to determine the wiggle time
ValidatorContract string `json:"validatorContract"` // Validator set contract
StateReceiverContract string `json:"stateReceiverContract"` // State receiver contract
}