mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-06 19:06:42 +01:00
Sync ForgerCommitment and use it in coord
Previously the coordinator was erroneously using Slot.BatchesLen to determine when anyone can forge. The correct behaviour is implmenented with the boolean flag `ForgerCommitment`, that is set to true only when there's a batch before the deadline within a slot. Delete Slot.BatchesLen, and the synchronization code of this value from the Synchronizer, as this is not needed
This commit is contained in:
@@ -177,17 +177,12 @@ type SCConsts struct {
|
||||
|
||||
// Config is the Synchronizer configuration
|
||||
type Config struct {
|
||||
// StartBlockNum StartBlockNum
|
||||
// InitialVariables SCVariables
|
||||
StatsRefreshPeriod time.Duration
|
||||
}
|
||||
|
||||
// Synchronizer implements the Synchronizer type
|
||||
type Synchronizer struct {
|
||||
ethClient eth.ClientInterface
|
||||
// auctionConstants common.AuctionConstants
|
||||
// rollupConstants common.RollupConstants
|
||||
// wDelayerConstants common.WDelayerConstants
|
||||
ethClient eth.ClientInterface
|
||||
consts SCConsts
|
||||
historyDB *historydb.HistoryDB
|
||||
stateDB *statedb.StateDB
|
||||
@@ -196,8 +191,6 @@ type Synchronizer struct {
|
||||
startBlockNum int64
|
||||
vars SCVariables
|
||||
stats *StatsHolder
|
||||
// firstSavedBlock *common.Block
|
||||
// mux sync.Mutex
|
||||
}
|
||||
|
||||
// NewSynchronizer creates a new Synchronizer
|
||||
@@ -286,24 +279,28 @@ func (s *Synchronizer) SCVars() SCVariablesPtr {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Synchronizer) updateCurrentSlotIfSync(batchesLen int) error {
|
||||
// firstBatchBlockNum is the blockNum of first batch in that block, if any
|
||||
func (s *Synchronizer) updateCurrentSlotIfSync(reset bool, firstBatchBlockNum *int64) error {
|
||||
slot := common.Slot{
|
||||
SlotNum: s.stats.Sync.Auction.CurrentSlot.SlotNum,
|
||||
BatchesLen: int(s.stats.Sync.Auction.CurrentSlot.BatchesLen),
|
||||
SlotNum: s.stats.Sync.Auction.CurrentSlot.SlotNum,
|
||||
ForgerCommitment: s.stats.Sync.Auction.CurrentSlot.ForgerCommitment,
|
||||
}
|
||||
// We want the next block because the current one is already mined
|
||||
blockNum := s.stats.Sync.LastBlock.Num + 1
|
||||
slotNum := s.consts.Auction.SlotNum(blockNum)
|
||||
if batchesLen == -1 {
|
||||
dbBatchesLen, err := s.historyDB.GetBatchesLen(slotNum)
|
||||
if err != nil {
|
||||
return tracerr.Wrap(fmt.Errorf("historyDB.GetBatchesLen: %w", err))
|
||||
if reset {
|
||||
dbFirstBatchBlockNum, err := s.historyDB.GetFirstBatchBlockNumBySlot(slotNum)
|
||||
if err != nil && tracerr.Unwrap(err) != sql.ErrNoRows {
|
||||
return tracerr.Wrap(fmt.Errorf("historyDB.GetFirstBatchBySlot: %w", err))
|
||||
} else if tracerr.Unwrap(err) == sql.ErrNoRows {
|
||||
firstBatchBlockNum = nil
|
||||
} else {
|
||||
firstBatchBlockNum = &dbFirstBatchBlockNum
|
||||
}
|
||||
slot.BatchesLen = dbBatchesLen
|
||||
slot.ForgerCommitment = false
|
||||
} else if slotNum > slot.SlotNum {
|
||||
slot.BatchesLen = batchesLen
|
||||
} else {
|
||||
slot.BatchesLen += batchesLen
|
||||
// We are in a new slotNum, start from default values
|
||||
slot.ForgerCommitment = false
|
||||
}
|
||||
slot.SlotNum = slotNum
|
||||
slot.StartBlock, slot.EndBlock = s.consts.Auction.SlotBlocks(slot.SlotNum)
|
||||
@@ -333,6 +330,11 @@ func (s *Synchronizer) updateCurrentSlotIfSync(batchesLen int) error {
|
||||
slot.URL = s.vars.Auction.BootCoordinatorURL
|
||||
}
|
||||
}
|
||||
if firstBatchBlockNum != nil &&
|
||||
s.consts.Auction.RelativeBlock(*firstBatchBlockNum) <
|
||||
int64(s.vars.Auction.SlotDeadline) {
|
||||
slot.ForgerCommitment = true
|
||||
}
|
||||
|
||||
// TODO: Remove this SANITY CHECK once this code is tested enough
|
||||
// BEGIN SANITY CHECK
|
||||
@@ -499,11 +501,6 @@ func (s *Synchronizer) Sync2(ctx context.Context, lastSavedBlock *common.Block)
|
||||
WDelayer: *wDelayerData,
|
||||
}
|
||||
|
||||
// log.Debugw("Sync()", "block", blockData)
|
||||
// err = s.historyDB.AddBlock(blockData.Block)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
err = s.historyDB.AddBlockSCData(&blockData)
|
||||
if err != nil {
|
||||
return nil, nil, tracerr.Wrap(err)
|
||||
@@ -522,9 +519,14 @@ func (s *Synchronizer) Sync2(ctx context.Context, lastSavedBlock *common.Block)
|
||||
}
|
||||
}
|
||||
s.stats.UpdateSync(ethBlock,
|
||||
&rollupData.Batches[batchesLen-1].Batch.BatchNum, lastL1BatchBlock, lastForgeL1TxsNum)
|
||||
&rollupData.Batches[batchesLen-1].Batch.BatchNum,
|
||||
lastL1BatchBlock, lastForgeL1TxsNum)
|
||||
}
|
||||
if err := s.updateCurrentSlotIfSync(len(rollupData.Batches)); err != nil {
|
||||
var firstBatchBlockNum *int64
|
||||
if len(rollupData.Batches) > 0 {
|
||||
firstBatchBlockNum = &rollupData.Batches[0].Batch.EthBlockNum
|
||||
}
|
||||
if err := s.updateCurrentSlotIfSync(false, firstBatchBlockNum); err != nil {
|
||||
return nil, nil, tracerr.Wrap(err)
|
||||
}
|
||||
|
||||
@@ -674,7 +676,7 @@ func (s *Synchronizer) resetState(block *common.Block) error {
|
||||
|
||||
s.stats.UpdateSync(block, &batchNum, &lastL1BatchBlockNum, lastForgeL1TxsNum)
|
||||
|
||||
if err := s.updateCurrentSlotIfSync(-1); err != nil {
|
||||
if err := s.updateCurrentSlotIfSync(true, nil); err != nil {
|
||||
return tracerr.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -271,18 +271,25 @@ func ethAddTokens(blocks []common.BlockData, client *test.Client) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSync(t *testing.T) {
|
||||
//
|
||||
// Setup
|
||||
//
|
||||
var chainID uint16 = 0
|
||||
var deleteme = []string{}
|
||||
|
||||
ctx := context.Background()
|
||||
func TestMain(m *testing.M) {
|
||||
exitVal := m.Run()
|
||||
for _, dir := range deleteme {
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
os.Exit(exitVal)
|
||||
}
|
||||
|
||||
func newTestModules(t *testing.T) (*statedb.StateDB, *historydb.HistoryDB) {
|
||||
// Int State DB
|
||||
dir, err := ioutil.TempDir("", "tmpdb")
|
||||
require.NoError(t, err)
|
||||
defer assert.Nil(t, os.RemoveAll(dir))
|
||||
deleteme = append(deleteme, dir)
|
||||
|
||||
chainID := uint16(0)
|
||||
stateDB, err := statedb.NewStateDB(dir, statedb.TypeSynchronizer, 32, chainID)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -294,9 +301,20 @@ func TestSync(t *testing.T) {
|
||||
// Clear DB
|
||||
test.WipeDB(historyDB.DB())
|
||||
|
||||
return stateDB, historyDB
|
||||
}
|
||||
|
||||
func TestSyncGeneral(t *testing.T) {
|
||||
//
|
||||
// Setup
|
||||
//
|
||||
|
||||
stateDB, historyDB := newTestModules(t)
|
||||
|
||||
// Init eth client
|
||||
var timer timer
|
||||
clientSetup := test.NewClientSetupExample()
|
||||
clientSetup.ChainID = big.NewInt(int64(chainID))
|
||||
bootCoordAddr := clientSetup.AuctionVariables.BootCoordinator
|
||||
client := test.NewClient(true, &timer, ðCommon.Address{}, clientSetup)
|
||||
|
||||
@@ -306,6 +324,8 @@ func TestSync(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
//
|
||||
// First Sync from an initial state
|
||||
//
|
||||
@@ -659,3 +679,129 @@ func TestSync(t *testing.T) {
|
||||
assert.Equal(t, 2, len(dbAccounts))
|
||||
assertEqualAccountsHistoryDBStateDB(t, dbAccounts, sdbAccounts)
|
||||
}
|
||||
|
||||
func TestSyncForgerCommitment(t *testing.T) {
|
||||
stateDB, historyDB := newTestModules(t)
|
||||
|
||||
// Init eth client
|
||||
var timer timer
|
||||
clientSetup := test.NewClientSetupExample()
|
||||
clientSetup.ChainID = big.NewInt(int64(chainID))
|
||||
clientSetup.AuctionConstants.GenesisBlockNum = 2
|
||||
clientSetup.AuctionConstants.BlocksPerSlot = 4
|
||||
clientSetup.AuctionVariables.SlotDeadline = 2
|
||||
bootCoordAddr := clientSetup.AuctionVariables.BootCoordinator
|
||||
client := test.NewClient(true, &timer, ðCommon.Address{}, clientSetup)
|
||||
|
||||
// Create Synchronizer
|
||||
s, err := NewSynchronizer(client, historyDB, stateDB, Config{
|
||||
StatsRefreshPeriod: 0 * time.Second,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
set := `
|
||||
Type: Blockchain
|
||||
|
||||
// Slot = 0
|
||||
|
||||
> block // 2
|
||||
> block // 3
|
||||
> block // 4
|
||||
> block // 5
|
||||
|
||||
// Slot = 1
|
||||
|
||||
> block // 6
|
||||
> batch
|
||||
> block // 7
|
||||
> block // 8
|
||||
> block // 9
|
||||
|
||||
// Slot = 2
|
||||
|
||||
> block // 10
|
||||
> block // 11
|
||||
> batch
|
||||
> block // 12
|
||||
> block // 13
|
||||
|
||||
`
|
||||
// For each block, true when the slot that belongs to the following
|
||||
// block has forgerCommitment
|
||||
commitment := map[int64]bool{
|
||||
2: false,
|
||||
3: false,
|
||||
4: false,
|
||||
5: false,
|
||||
|
||||
6: false,
|
||||
7: true,
|
||||
8: true,
|
||||
9: false,
|
||||
|
||||
10: false,
|
||||
11: false,
|
||||
12: false,
|
||||
13: false,
|
||||
}
|
||||
tc := til.NewContext(chainID, common.RollupConstMaxL1UserTx)
|
||||
blocks, err := tc.GenerateBlocks(set)
|
||||
assert.NoError(t, err)
|
||||
|
||||
tilCfgExtra := til.ConfigExtra{
|
||||
BootCoordAddr: bootCoordAddr,
|
||||
CoordUser: "A",
|
||||
}
|
||||
err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
|
||||
require.NoError(t, err)
|
||||
|
||||
// for i := range blocks {
|
||||
// for j := range blocks[i].Rollup.Batches {
|
||||
// blocks[i].Rollup.Batches[j].Batch.SlotNum = int64(i) / 4
|
||||
// }
|
||||
// }
|
||||
|
||||
// be in sync
|
||||
for {
|
||||
syncBlock, discards, err := s.Sync2(ctx, nil)
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, discards)
|
||||
if syncBlock == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
stats := s.Stats()
|
||||
require.Equal(t, int64(1), stats.Sync.LastBlock.Num)
|
||||
|
||||
// Store ForgerComitmnent observed at every block by the live synchronizer
|
||||
syncCommitment := map[int64]bool{}
|
||||
// Store ForgerComitmnent observed at every block by a syncrhonizer that is restarted
|
||||
syncRestartedCommitment := map[int64]bool{}
|
||||
for _, block := range blocks {
|
||||
// Add block data to the smart contracts
|
||||
err = client.CtlAddBlocks([]common.BlockData{block})
|
||||
require.NoError(t, err)
|
||||
|
||||
syncBlock, discards, err := s.Sync2(ctx, nil)
|
||||
require.NoError(t, err)
|
||||
require.Nil(t, discards)
|
||||
if syncBlock == nil {
|
||||
break
|
||||
}
|
||||
stats := s.Stats()
|
||||
require.True(t, stats.Synced())
|
||||
syncCommitment[syncBlock.Block.Num] = stats.Sync.Auction.CurrentSlot.ForgerCommitment
|
||||
|
||||
s2, err := NewSynchronizer(client, historyDB, stateDB, Config{
|
||||
StatsRefreshPeriod: 0 * time.Second,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
stats = s2.Stats()
|
||||
require.True(t, stats.Synced())
|
||||
syncRestartedCommitment[syncBlock.Block.Num] = stats.Sync.Auction.CurrentSlot.ForgerCommitment
|
||||
}
|
||||
assert.Equal(t, commitment, syncCommitment)
|
||||
assert.Equal(t, commitment, syncRestartedCommitment)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user