Browse Source

Extend Coordinator tests

feature/sql-semaphore1
Eduard S 3 years ago
parent
commit
6a9b5ce420
12 changed files with 325 additions and 89 deletions
  1. +5
    -0
      batchbuilder/batchbuilder.go
  2. +2
    -0
      coordinator/batch.go
  3. +20
    -12
      coordinator/coordinator.go
  4. +219
    -20
      coordinator/coordinator_test.go
  5. +3
    -0
      coordinator/purger.go
  6. +7
    -1
      db/statedb/statedb.go
  7. +1
    -1
      go.mod
  8. +2
    -0
      go.sum
  9. +10
    -10
      prover/prover.go
  10. +1
    -1
      prover/prover_test.go
  11. +8
    -44
      synchronizer/synchronizer_test.go
  12. +47
    -0
      test/ethclient.go

+ 5
- 0
batchbuilder/batchbuilder.go

@ -63,3 +63,8 @@ func (bb *BatchBuilder) BuildBatch(coordIdxs []common.Idx, configBatch *ConfigBa
ptOut, err := bb.localStateDB.ProcessTxs(ptc, coordIdxs, l1usertxs, l1coordinatortxs, pooll2txs) ptOut, err := bb.localStateDB.ProcessTxs(ptc, coordIdxs, l1usertxs, l1coordinatortxs, pooll2txs)
return ptOut.ZKInputs, tracerr.Wrap(err) return ptOut.ZKInputs, tracerr.Wrap(err)
} }
// LocalStateDB returns the underlying LocalStateDB
func (bb *BatchBuilder) LocalStateDB() *statedb.LocalStateDB {
return bb.localStateDB
}

+ 2
- 0
coordinator/batch.go

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math/big"
"path" "path"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
@ -29,6 +30,7 @@ type BatchInfo struct {
ServerProof prover.Client ServerProof prover.Client
ZKInputs *common.ZKInputs ZKInputs *common.ZKInputs
Proof *prover.Proof Proof *prover.Proof
PublicInputs []*big.Int
L1UserTxsExtra []common.L1Tx L1UserTxsExtra []common.L1Tx
L1CoordTxs []common.L1Tx L1CoordTxs []common.L1Tx
L2Txs []common.PoolL2Tx L2Txs []common.PoolL2Tx

+ 20
- 12
coordinator/coordinator.go

@ -638,22 +638,14 @@ func (p *Pipeline) SetSyncStats(stats *synchronizer.Stats) {
p.statsCh <- *stats p.statsCh <- *stats
} }
// Start the forging pipeline
func (p *Pipeline) Start(batchNum common.BatchNum, lastForgeL1TxsNum int64,
syncStats *synchronizer.Stats, initSCVars *synchronizer.SCVariables) error {
if p.started {
log.Fatal("Pipeline already started")
}
p.started = true
// Reset pipeline state
// reset pipeline state
func (p *Pipeline) reset(batchNum common.BatchNum, lastForgeL1TxsNum int64,
initSCVars *synchronizer.SCVariables) error {
p.batchNum = batchNum p.batchNum = batchNum
p.lastForgeL1TxsNum = lastForgeL1TxsNum p.lastForgeL1TxsNum = lastForgeL1TxsNum
p.vars = *initSCVars p.vars = *initSCVars
p.lastScheduledL1BatchBlockNum = 0 p.lastScheduledL1BatchBlockNum = 0
p.ctx, p.cancel = context.WithCancel(context.Background())
err := p.txSelector.Reset(p.batchNum) err := p.txSelector.Reset(p.batchNum)
if err != nil { if err != nil {
return tracerr.Wrap(err) return tracerr.Wrap(err)
@ -662,6 +654,21 @@ func (p *Pipeline) Start(batchNum common.BatchNum, lastForgeL1TxsNum int64,
if err != nil { if err != nil {
return tracerr.Wrap(err) return tracerr.Wrap(err)
} }
return nil
}
// Start the forging pipeline
func (p *Pipeline) Start(batchNum common.BatchNum, lastForgeL1TxsNum int64,
syncStats *synchronizer.Stats, initSCVars *synchronizer.SCVariables) error {
if p.started {
log.Fatal("Pipeline already started")
}
p.started = true
if err := p.reset(batchNum, lastForgeL1TxsNum, initSCVars); err != nil {
return tracerr.Wrap(err)
}
p.ctx, p.cancel = context.WithCancel(context.Background())
queueSize := 1 queueSize := 1
batchChSentServerProof := make(chan *BatchInfo, queueSize) batchChSentServerProof := make(chan *BatchInfo, queueSize)
@ -840,13 +847,14 @@ func (p *Pipeline) forgeSendServerProof(ctx context.Context, batchNum common.Bat
// waitServerProof gets the generated zkProof & sends it to the SmartContract // waitServerProof gets the generated zkProof & sends it to the SmartContract
func (p *Pipeline) waitServerProof(ctx context.Context, batchInfo *BatchInfo) error { func (p *Pipeline) waitServerProof(ctx context.Context, batchInfo *BatchInfo) error {
proof, err := batchInfo.ServerProof.GetProof(ctx) // blocking call, until not resolved don't continue. Returns when the proof server has calculated the proof
proof, pubInputs, err := batchInfo.ServerProof.GetProof(ctx) // blocking call, until not resolved don't continue. Returns when the proof server has calculated the proof
if err != nil { if err != nil {
return tracerr.Wrap(err) return tracerr.Wrap(err)
} }
p.proversPool.Add(batchInfo.ServerProof) p.proversPool.Add(batchInfo.ServerProof)
batchInfo.ServerProof = nil batchInfo.ServerProof = nil
batchInfo.Proof = proof batchInfo.Proof = proof
batchInfo.PublicInputs = pubInputs
batchInfo.ForgeBatchArgs = p.prepareForgeBatchArgs(batchInfo) batchInfo.ForgeBatchArgs = p.prepareForgeBatchArgs(batchInfo)
batchInfo.TxStatus = TxStatusPending batchInfo.TxStatus = TxStatusPending
p.cfg.debugBatchStore(batchInfo) p.cfg.debugBatchStore(batchInfo)

+ 219
- 20
coordinator/coordinator_test.go

@ -11,14 +11,17 @@ import (
ethCommon "github.com/ethereum/go-ethereum/common" ethCommon "github.com/ethereum/go-ethereum/common"
"github.com/hermeznetwork/hermez-node/batchbuilder" "github.com/hermeznetwork/hermez-node/batchbuilder"
"github.com/hermeznetwork/hermez-node/common"
dbUtils "github.com/hermeznetwork/hermez-node/db" dbUtils "github.com/hermeznetwork/hermez-node/db"
"github.com/hermeznetwork/hermez-node/db/historydb" "github.com/hermeznetwork/hermez-node/db/historydb"
"github.com/hermeznetwork/hermez-node/db/l2db" "github.com/hermeznetwork/hermez-node/db/l2db"
"github.com/hermeznetwork/hermez-node/db/statedb" "github.com/hermeznetwork/hermez-node/db/statedb"
"github.com/hermeznetwork/hermez-node/eth"
"github.com/hermeznetwork/hermez-node/log" "github.com/hermeznetwork/hermez-node/log"
"github.com/hermeznetwork/hermez-node/prover" "github.com/hermeznetwork/hermez-node/prover"
"github.com/hermeznetwork/hermez-node/synchronizer" "github.com/hermeznetwork/hermez-node/synchronizer"
"github.com/hermeznetwork/hermez-node/test" "github.com/hermeznetwork/hermez-node/test"
"github.com/hermeznetwork/hermez-node/test/til"
"github.com/hermeznetwork/hermez-node/txselector" "github.com/hermeznetwork/hermez-node/txselector"
"github.com/hermeznetwork/tracerr" "github.com/hermeznetwork/tracerr"
"github.com/iden3/go-merkletree/db/pebble" "github.com/iden3/go-merkletree/db/pebble"
@ -73,15 +76,29 @@ var syncDBPath string
var txSelDBPath string var txSelDBPath string
var batchBuilderDBPath string var batchBuilderDBPath string
func newTestModules(t *testing.T) (*historydb.HistoryDB, *l2db.L2DB,
*txselector.TxSelector, *batchbuilder.BatchBuilder) { // FUTURE once Synchronizer is ready, should return it also
type modules struct {
historyDB *historydb.HistoryDB
l2DB *l2db.L2DB
txSelector *txselector.TxSelector
batchBuilder *batchbuilder.BatchBuilder
stateDB *statedb.StateDB
}
var maxL1UserTxs uint64 = 128
var maxL1Txs uint64 = 256
var maxL1CoordinatorTxs uint64 = maxL1Txs - maxL1UserTxs
var maxTxs uint64 = 376
var nLevels uint32 = 32 //nolint:deadcode,unused
var maxFeeTxs uint32 = 64 //nolint:deadcode,varcheck
func newTestModules(t *testing.T) modules {
nLevels := 32 nLevels := 32
var err error var err error
syncDBPath, err = ioutil.TempDir("", "tmpSyncDB") syncDBPath, err = ioutil.TempDir("", "tmpSyncDB")
require.NoError(t, err) require.NoError(t, err)
deleteme = append(deleteme, syncDBPath) deleteme = append(deleteme, syncDBPath)
syncSdb, err := statedb.NewStateDB(syncDBPath, statedb.TypeSynchronizer, nLevels)
syncStateDB, err := statedb.NewStateDB(syncDBPath, statedb.TypeSynchronizer, nLevels)
assert.NoError(t, err) assert.NoError(t, err)
pass := os.Getenv("POSTGRES_PASS") pass := os.Getenv("POSTGRES_PASS")
@ -94,18 +111,22 @@ func newTestModules(t *testing.T) (*historydb.HistoryDB, *l2db.L2DB,
txSelDBPath, err = ioutil.TempDir("", "tmpTxSelDB") txSelDBPath, err = ioutil.TempDir("", "tmpTxSelDB")
require.NoError(t, err) require.NoError(t, err)
deleteme = append(deleteme, txSelDBPath) deleteme = append(deleteme, txSelDBPath)
txsel, err := txselector.NewTxSelector(txSelDBPath, syncSdb, l2DB, 10, 10, 10)
txSelector, err := txselector.NewTxSelector(txSelDBPath, syncStateDB, l2DB, maxL1UserTxs, maxL1CoordinatorTxs, maxTxs)
assert.NoError(t, err) assert.NoError(t, err)
batchBuilderDBPath, err = ioutil.TempDir("", "tmpBatchBuilderDB") batchBuilderDBPath, err = ioutil.TempDir("", "tmpBatchBuilderDB")
require.NoError(t, err) require.NoError(t, err)
deleteme = append(deleteme, batchBuilderDBPath) deleteme = append(deleteme, batchBuilderDBPath)
bb, err := batchbuilder.NewBatchBuilder(batchBuilderDBPath, syncSdb, nil, 0, uint64(nLevels))
batchBuilder, err := batchbuilder.NewBatchBuilder(batchBuilderDBPath, syncStateDB, nil, 0, uint64(nLevels))
assert.NoError(t, err) assert.NoError(t, err)
// l1Txs, coordinatorL1Txs, poolL2Txs := test.GenerateTestTxsFromSet(t, test.SetTest0)
return historyDB, l2DB, txsel, bb
return modules{
historyDB: historyDB,
l2DB: l2DB,
txSelector: txSelector,
batchBuilder: batchBuilder,
stateDB: syncStateDB,
}
} }
type timer struct { type timer struct {
@ -121,9 +142,8 @@ func (t *timer) Time() int64 {
var bidder = ethCommon.HexToAddress("0x6b175474e89094c44da98b954eedeac495271d0f") var bidder = ethCommon.HexToAddress("0x6b175474e89094c44da98b954eedeac495271d0f")
var forger = ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6") var forger = ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
func newTestCoordinator(t *testing.T, forgerAddr ethCommon.Address, ethClient *test.Client, ethClientSetup *test.ClientSetup) *Coordinator {
historyDB, l2DB, txsel, bb := newTestModules(t)
func newTestCoordinator(t *testing.T, forgerAddr ethCommon.Address, ethClient *test.Client,
ethClientSetup *test.ClientSetup, modules modules) *Coordinator {
debugBatchPath, err := ioutil.TempDir("", "tmpDebugBatch") debugBatchPath, err := ioutil.TempDir("", "tmpDebugBatch")
require.NoError(t, err) require.NoError(t, err)
deleteme = append(deleteme, debugBatchPath) deleteme = append(deleteme, debugBatchPath)
@ -149,12 +169,38 @@ func newTestCoordinator(t *testing.T, forgerAddr ethCommon.Address, ethClient *t
Auction: *ethClientSetup.AuctionVariables, Auction: *ethClientSetup.AuctionVariables,
WDelayer: *ethClientSetup.WDelayerVariables, WDelayer: *ethClientSetup.WDelayerVariables,
} }
coord, err := NewCoordinator(conf, historyDB, l2DB, txsel, bb, serverProofs,
ethClient, scConsts, initSCVars)
coord, err := NewCoordinator(conf, modules.historyDB, modules.l2DB, modules.txSelector,
modules.batchBuilder, serverProofs, ethClient, scConsts, initSCVars)
require.NoError(t, err) require.NoError(t, err)
return coord return coord
} }
func newTestSynchronizer(t *testing.T, ethClient *test.Client, ethClientSetup *test.ClientSetup,
modules modules) *synchronizer.Synchronizer {
sync, err := synchronizer.NewSynchronizer(ethClient, modules.historyDB, modules.stateDB,
synchronizer.Config{
StartBlockNum: synchronizer.ConfigStartBlockNum{
Rollup: 1,
Auction: 1,
WDelayer: 1,
},
InitialVariables: synchronizer.SCVariables{
Rollup: *ethClientSetup.RollupVariables,
Auction: *ethClientSetup.AuctionVariables,
WDelayer: *ethClientSetup.WDelayerVariables,
},
})
require.NoError(t, err)
return sync
}
// TestCoordinatorFlow is a test where the coordinator is stared (which means
// that goroutines are spawned), and ethereum blocks are mined via the
// test.Client to simulate starting and stopping forging times. This test
// works without a synchronizer, and no l2txs are inserted in the pool, so all
// the batches are forged empty. The purpose of this test is to manually
// observe via the logs that nothing crashes and that the coordinator starts
// and stops forging at the right blocks.
func TestCoordinatorFlow(t *testing.T) { func TestCoordinatorFlow(t *testing.T) {
if os.Getenv("TEST_COORD_FLOW") == "" { if os.Getenv("TEST_COORD_FLOW") == "" {
return return
@ -162,7 +208,8 @@ func TestCoordinatorFlow(t *testing.T) {
ethClientSetup := test.NewClientSetupExample() ethClientSetup := test.NewClientSetupExample()
var timer timer var timer timer
ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup) ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
coord := newTestCoordinator(t, forger, ethClient, ethClientSetup)
modules := newTestModules(t)
coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
// Bid for slot 2 and 4 // Bid for slot 2 and 4
_, err := ethClient.AuctionSetCoordinator(forger, "https://foo.bar") _, err := ethClient.AuctionSetCoordinator(forger, "https://foo.bar")
@ -242,7 +289,8 @@ func TestCoordinatorStartStop(t *testing.T) {
ethClientSetup := test.NewClientSetupExample() ethClientSetup := test.NewClientSetupExample()
var timer timer var timer timer
ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup) ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
coord := newTestCoordinator(t, forger, ethClient, ethClientSetup)
modules := newTestModules(t)
coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
coord.Start() coord.Start()
coord.Stop() coord.Stop()
} }
@ -253,13 +301,15 @@ func TestCoordCanForge(t *testing.T) {
var timer timer var timer timer
ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup) ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
coord := newTestCoordinator(t, forger, ethClient, ethClientSetup)
modules := newTestModules(t)
coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
_, err := ethClient.AuctionSetCoordinator(forger, "https://foo.bar") _, err := ethClient.AuctionSetCoordinator(forger, "https://foo.bar")
require.NoError(t, err) require.NoError(t, err)
_, err = ethClient.AuctionBidSimple(2, big.NewInt(9999)) _, err = ethClient.AuctionBidSimple(2, big.NewInt(9999))
require.NoError(t, err) require.NoError(t, err)
bootCoord := newTestCoordinator(t, bootForger, ethClient, ethClientSetup)
modules2 := newTestModules(t)
bootCoord := newTestCoordinator(t, bootForger, ethClient, ethClientSetup, modules2)
assert.Equal(t, forger, coord.cfg.ForgerAddress) assert.Equal(t, forger, coord.cfg.ForgerAddress)
assert.Equal(t, bootForger, bootCoord.cfg.ForgerAddress) assert.Equal(t, bootForger, bootCoord.cfg.ForgerAddress)
@ -293,13 +343,14 @@ func TestCoordCanForge(t *testing.T) {
assert.Equal(t, false, bootCoord.canForge(&stats)) assert.Equal(t, false, bootCoord.canForge(&stats))
} }
func TestCoordHandleMsgSyncStats(t *testing.T) {
func TestCoordHandleMsgSyncBlock(t *testing.T) {
ethClientSetup := test.NewClientSetupExample() ethClientSetup := test.NewClientSetupExample()
bootForger := ethClientSetup.AuctionVariables.BootCoordinator bootForger := ethClientSetup.AuctionVariables.BootCoordinator
var timer timer var timer timer
ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup) ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
coord := newTestCoordinator(t, forger, ethClient, ethClientSetup)
modules := newTestModules(t)
coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
_, err := ethClient.AuctionSetCoordinator(forger, "https://foo.bar") _, err := ethClient.AuctionSetCoordinator(forger, "https://foo.bar")
require.NoError(t, err) require.NoError(t, err)
_, err = ethClient.AuctionBidSimple(2, big.NewInt(9999)) _, err = ethClient.AuctionBidSimple(2, big.NewInt(9999))
@ -355,7 +406,8 @@ func TestPipelineShouldL1L2Batch(t *testing.T) {
var timer timer var timer timer
ctx := context.Background() ctx := context.Background()
ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup) ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
coord := newTestCoordinator(t, forger, ethClient, ethClientSetup)
modules := newTestModules(t)
coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
pipeline, err := coord.newPipeline(ctx) pipeline, err := coord.newPipeline(ctx)
require.NoError(t, err) require.NoError(t, err)
pipeline.vars = coord.vars pipeline.vars = coord.vars
@ -414,6 +466,153 @@ func TestPipelineShouldL1L2Batch(t *testing.T) {
assert.Equal(t, true, pipeline.shouldL1L2Batch()) assert.Equal(t, true, pipeline.shouldL1L2Batch())
} }
// ethAddTokens adds the tokens from the blocks to the blockchain
func ethAddTokens(blocks []common.BlockData, client *test.Client) {
for _, block := range blocks {
for _, token := range block.Rollup.AddedTokens {
consts := eth.ERC20Consts{
Name: fmt.Sprintf("Token %d", token.TokenID),
Symbol: fmt.Sprintf("TK%d", token.TokenID),
Decimals: 18,
}
// tokenConsts[token.TokenID] = consts
client.CtlAddERC20(token.EthAddr, consts)
}
}
}
const testTokensLen = 3
const testUsersLen = 4
func preloadSync(t *testing.T, ethClient *test.Client, sync *synchronizer.Synchronizer,
historyDB *historydb.HistoryDB, stateDB *statedb.StateDB) *til.Context {
// Create a set with `testTokensLen` tokens and for each token
// `testUsersLen` accounts.
var set []til.Instruction
// set = append(set, til.Instruction{Typ: "Blockchain"})
for tokenID := 1; tokenID < testTokensLen; tokenID++ {
set = append(set, til.Instruction{
Typ: til.TypeAddToken,
TokenID: common.TokenID(tokenID),
})
}
depositAmount, ok := new(big.Int).SetString("10225000000000000000000000000000000", 10)
require.True(t, ok)
for tokenID := 0; tokenID < testTokensLen; tokenID++ {
for user := 0; user < testUsersLen; user++ {
set = append(set, til.Instruction{
Typ: common.TxTypeCreateAccountDeposit,
TokenID: common.TokenID(tokenID),
DepositAmount: depositAmount,
From: fmt.Sprintf("User%d", user),
})
}
}
set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
set = append(set, til.Instruction{Typ: til.TypeNewBatchL1})
set = append(set, til.Instruction{Typ: til.TypeNewBlock})
tc := til.NewContext(common.RollupConstMaxL1UserTx)
blocks, err := tc.GenerateBlocksFromInstructions(set)
require.NoError(t, err)
require.NotNil(t, blocks)
ethAddTokens(blocks, ethClient)
err = ethClient.CtlAddBlocks(blocks)
require.NoError(t, err)
ctx := context.Background()
for {
syncBlock, discards, err := sync.Sync2(ctx, nil)
require.NoError(t, err)
require.Nil(t, discards)
if syncBlock == nil {
break
}
}
dbTokens, err := historyDB.GetAllTokens()
require.Nil(t, err)
require.Equal(t, testTokensLen, len(dbTokens))
dbAccounts, err := historyDB.GetAllAccounts()
require.Nil(t, err)
require.Equal(t, testTokensLen*testUsersLen, len(dbAccounts))
sdbAccounts, err := stateDB.GetAccounts()
require.Nil(t, err)
require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
return tc
}
func TestPipeline1(t *testing.T) {
ethClientSetup := test.NewClientSetupExample()
var timer timer
ctx := context.Background()
ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
modules := newTestModules(t)
coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
sync := newTestSynchronizer(t, ethClient, ethClientSetup, modules)
pipeline, err := coord.newPipeline(ctx)
require.NoError(t, err)
require.NotNil(t, sync)
require.NotNil(t, pipeline)
// preload the synchronier (via the test ethClient) some tokens and
// users with positive balances
tilCtx := preloadSync(t, ethClient, sync, modules.historyDB, modules.stateDB)
syncStats := sync.Stats()
batchNum := common.BatchNum(syncStats.Sync.LastBatch)
syncSCVars := sync.SCVars()
// Insert some l2txs in the Pool
setPool := `
Type: PoolL2
PoolTransfer(0) User0-User1: 100 (126)
PoolTransfer(0) User1-User2: 200 (126)
PoolTransfer(0) User2-User3: 300 (126)
`
l2txs, err := tilCtx.GeneratePoolL2Txs(setPool)
require.NoError(t, err)
for _, tx := range l2txs {
err := modules.l2DB.AddTxTest(&tx) //nolint:gosec
require.NoError(t, err)
}
err = pipeline.reset(batchNum, syncStats.Sync.LastForgeL1TxsNum, &synchronizer.SCVariables{
Rollup: *syncSCVars.Rollup,
Auction: *syncSCVars.Auction,
WDelayer: *syncSCVars.WDelayer,
})
require.NoError(t, err)
// Sanity check
sdbAccounts, err := pipeline.txSelector.LocalAccountsDB().GetAccounts()
require.Nil(t, err)
require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
// Sanity check
sdbAccounts, err = pipeline.batchBuilder.LocalStateDB().GetAccounts()
require.Nil(t, err)
require.Equal(t, testTokensLen*testUsersLen, len(sdbAccounts))
// Sanity check
require.Equal(t, modules.stateDB.MerkleTree().Root(),
pipeline.batchBuilder.LocalStateDB().MerkleTree().Root())
batchNum++
batchInfo, err := pipeline.forgeSendServerProof(ctx, batchNum)
require.NoError(t, err)
assert.Equal(t, 3, len(batchInfo.L2Txs))
batchNum++
batchInfo, err = pipeline.forgeSendServerProof(ctx, batchNum)
require.NoError(t, err)
assert.Equal(t, 0, len(batchInfo.L2Txs))
}
// TODO: Test Reorg // TODO: Test Reorg
// TODO: Test Pipeline // TODO: Test Pipeline
// TODO: Test TxMonitor // TODO: Test TxMonitor

+ 3
- 0
coordinator/purger.go

@ -143,8 +143,11 @@ func poolMarkInvalidOldNonces(l2DB *l2db.L2DB, stateDB *statedb.LocalStateDB,
return tracerr.Wrap(err) return tracerr.Wrap(err)
} else if idx <= lastIdx { } else if idx <= lastIdx {
return tracerr.Wrap(fmt.Errorf("account with idx %v not found: %w", idx, err)) return tracerr.Wrap(fmt.Errorf("account with idx %v not found: %w", idx, err))
} else {
return tracerr.Wrap(fmt.Errorf("unexpected stateDB error with idx %v: %w", idx, err))
} }
} }
fmt.Printf("DBG acc: %#v\n", acc)
idxsNonce[i].Idx = idx idxsNonce[i].Idx = idx
idxsNonce[i].Nonce = acc.Nonce idxsNonce[i].Nonce = acc.Nonce
} }

+ 7
- 1
db/statedb/statedb.go

@ -486,7 +486,8 @@ func updateAccountInTreeDB(sto db.Storage, mt *merkletree.MerkleTree, idx common
} }
if mt != nil { if mt != nil {
return mt.Update(idx.BigInt(), v)
proof, err := mt.Update(idx.BigInt(), v)
return proof, tracerr.Wrap(err)
} }
return nil, nil return nil, nil
} }
@ -504,6 +505,11 @@ func (s *StateDB) MTGetRoot() *big.Int {
return s.mt.Root().BigInt() return s.mt.Root().BigInt()
} }
// MerkleTree returns the underlying StateDB merkle tree. It can be nil.
func (s *StateDB) MerkleTree() *merkletree.MerkleTree {
return s.mt
}
// LocalStateDB represents the local StateDB which allows to make copies from // LocalStateDB represents the local StateDB which allows to make copies from
// the synchronizer StateDB, and is used by the tx-selector and the // the synchronizer StateDB, and is used by the tx-selector and the
// batch-builder. LocalStateDB is an in-memory storage. // batch-builder. LocalStateDB is an in-memory storage.

+ 1
- 1
go.mod

@ -14,7 +14,7 @@ require (
github.com/gobuffalo/packr/v2 v2.8.0 github.com/gobuffalo/packr/v2 v2.8.0
github.com/hermeznetwork/tracerr v0.3.1-0.20201126162137-de9930d0cf29 github.com/hermeznetwork/tracerr v0.3.1-0.20201126162137-de9930d0cf29
github.com/iden3/go-iden3-crypto v0.0.6-0.20201203095229-821a601d2002 github.com/iden3/go-iden3-crypto v0.0.6-0.20201203095229-821a601d2002
github.com/iden3/go-merkletree v0.0.0-20201203095330-4a8397a45644
github.com/iden3/go-merkletree v0.0.0-20201215142017-730707e5659a
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
github.com/jmoiron/sqlx v1.2.1-0.20200615141059-0794cb1f47ee github.com/jmoiron/sqlx v1.2.1-0.20200615141059-0794cb1f47ee
github.com/joho/godotenv v1.3.0 github.com/joho/godotenv v1.3.0

+ 2
- 0
go.sum

@ -331,6 +331,8 @@ github.com/iden3/go-merkletree v0.0.0-20201103115630-ad30c8309b44 h1:d6AbzJWWUos
github.com/iden3/go-merkletree v0.0.0-20201103115630-ad30c8309b44/go.mod h1:MRe6i0mi2oDVUzgBIHsNRE6XAg8EBuqIQZMsd+do+dU= github.com/iden3/go-merkletree v0.0.0-20201103115630-ad30c8309b44/go.mod h1:MRe6i0mi2oDVUzgBIHsNRE6XAg8EBuqIQZMsd+do+dU=
github.com/iden3/go-merkletree v0.0.0-20201203095330-4a8397a45644 h1:obSehuklDMDpmQ4j0d6RxU70bjRjEWlGlkO13CKp8Fw= github.com/iden3/go-merkletree v0.0.0-20201203095330-4a8397a45644 h1:obSehuklDMDpmQ4j0d6RxU70bjRjEWlGlkO13CKp8Fw=
github.com/iden3/go-merkletree v0.0.0-20201203095330-4a8397a45644/go.mod h1:MRe6i0mi2oDVUzgBIHsNRE6XAg8EBuqIQZMsd+do+dU= github.com/iden3/go-merkletree v0.0.0-20201203095330-4a8397a45644/go.mod h1:MRe6i0mi2oDVUzgBIHsNRE6XAg8EBuqIQZMsd+do+dU=
github.com/iden3/go-merkletree v0.0.0-20201215142017-730707e5659a h1:Wq5haqbfI0Ruht6nHotf+0HS5xAXKO17Xa6NBZVtTrM=
github.com/iden3/go-merkletree v0.0.0-20201215142017-730707e5659a/go.mod h1:MRe6i0mi2oDVUzgBIHsNRE6XAg8EBuqIQZMsd+do+dU=
github.com/iden3/go-wasm3 v0.0.1/go.mod h1:j+TcAB94Dfrjlu5kJt83h2OqAU+oyNUTwNZnQyII1sI= github.com/iden3/go-wasm3 v0.0.1/go.mod h1:j+TcAB94Dfrjlu5kJt83h2OqAU+oyNUTwNZnQyII1sI=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=

+ 10
- 10
prover/prover.go

@ -63,7 +63,7 @@ type Client interface {
// Non-blocking // Non-blocking
CalculateProof(ctx context.Context, zkInputs *common.ZKInputs) error CalculateProof(ctx context.Context, zkInputs *common.ZKInputs) error
// Blocking // Blocking
GetProof(ctx context.Context) (*Proof, error)
GetProof(ctx context.Context) (*Proof, []*big.Int, error)
// Non-Blocking // Non-Blocking
Cancel(ctx context.Context) error Cancel(ctx context.Context) error
// Blocking // Blocking
@ -209,23 +209,23 @@ func (p *ProofServerClient) CalculateProof(ctx context.Context, zkInputs *common
// GetProof retreives the Proof from the ServerProof, blocking until the proof // GetProof retreives the Proof from the ServerProof, blocking until the proof
// is ready. // is ready.
func (p *ProofServerClient) GetProof(ctx context.Context) (*Proof, error) {
func (p *ProofServerClient) GetProof(ctx context.Context) (*Proof, []*big.Int, error) {
if err := p.WaitReady(ctx); err != nil { if err := p.WaitReady(ctx); err != nil {
return nil, err
return nil, nil, err
} }
status, err := p.apiStatus(ctx) status, err := p.apiStatus(ctx)
if err != nil { if err != nil {
return nil, tracerr.Wrap(err)
return nil, nil, tracerr.Wrap(err)
} }
if status.Status == StatusCodeSuccess { if status.Status == StatusCodeSuccess {
var proof Proof var proof Proof
err := json.Unmarshal([]byte(status.Proof), &proof) err := json.Unmarshal([]byte(status.Proof), &proof)
if err != nil { if err != nil {
return nil, tracerr.Wrap(err)
return nil, nil, tracerr.Wrap(err)
} }
return &proof, nil
return &proof, nil, nil
} }
return nil, fmt.Errorf("status != StatusCodeSuccess, status = %v", status.Status)
return nil, nil, fmt.Errorf("status != StatusCodeSuccess, status = %v", status.Status)
} }
// Cancel cancels any current proof computation // Cancel cancels any current proof computation
@ -265,13 +265,13 @@ func (p *MockClient) CalculateProof(ctx context.Context, zkInputs *common.ZKInpu
} }
// GetProof retreives the Proof from the ServerProof // GetProof retreives the Proof from the ServerProof
func (p *MockClient) GetProof(ctx context.Context) (*Proof, error) {
func (p *MockClient) GetProof(ctx context.Context) (*Proof, []*big.Int, error) {
// Simulate a delay // Simulate a delay
select { select {
case <-time.After(500 * time.Millisecond): //nolint:gomnd case <-time.After(500 * time.Millisecond): //nolint:gomnd
return &Proof{}, nil
return &Proof{}, nil, nil
case <-ctx.Done(): case <-ctx.Done():
return nil, tracerr.Wrap(common.ErrDone)
return nil, nil, tracerr.Wrap(common.ErrDone)
} }
} }

+ 1
- 1
prover/prover_test.go

@ -53,7 +53,7 @@ func testCalculateProof(t *testing.T) {
} }
func testGetProof(t *testing.T) { func testGetProof(t *testing.T) {
proof, err := proofServerClient.GetProof(context.Background())
proof, _, err := proofServerClient.GetProof(context.Background())
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, proof) require.NotNil(t, proof)
require.NotNil(t, proof.PiA) require.NotNil(t, proof.PiA)

+ 8
- 44
synchronizer/synchronizer_test.go

@ -270,44 +270,6 @@ func ethAddTokens(blocks []common.BlockData, client *test.Client) {
} }
} }
// ethAddBlocks adds block data to the smart contracts
func ethAddBlocks(t *testing.T, blocks []common.BlockData,
client *test.Client, clientSetup *test.ClientSetup) {
for _, block := range blocks {
for _, token := range block.Rollup.AddedTokens {
_, err := client.RollupAddTokenSimple(token.EthAddr, clientSetup.RollupVariables.FeeAddToken)
require.Nil(t, err)
}
for _, tx := range block.Rollup.L1UserTxs {
client.CtlSetAddr(tx.FromEthAddr)
_, err := client.RollupL1UserTxERC20ETH(tx.FromBJJ, int64(tx.FromIdx), tx.DepositAmount, tx.Amount,
uint32(tx.TokenID), int64(tx.ToIdx))
require.Nil(t, err)
}
client.CtlSetAddr(clientSetup.AuctionVariables.BootCoordinator)
for _, batch := range block.Rollup.Batches {
_, err := client.RollupForgeBatch(&eth.RollupForgeBatchArgs{
NewLastIdx: batch.Batch.LastIdx,
NewStRoot: batch.Batch.StateRoot,
NewExitRoot: batch.Batch.ExitRoot,
L1CoordinatorTxs: batch.L1CoordinatorTxs,
L1CoordinatorTxsAuths: [][]byte{}, // Intentionally empty
L2TxsData: batch.L2Txs,
FeeIdxCoordinator: batch.Batch.FeeIdxsCoordinator,
// Circuit selector
VerifierIdx: 0, // Intentionally empty
L1Batch: batch.L1Batch,
ProofA: [2]*big.Int{}, // Intentionally empty
ProofB: [2][2]*big.Int{}, // Intentionally empty
ProofC: [2]*big.Int{}, // Intentionally empty
})
require.Nil(t, err)
}
// Mine block and sync
client.CtlMineBlock()
}
}
func TestSync(t *testing.T) { func TestSync(t *testing.T) {
// //
// Setup // Setup
@ -320,7 +282,7 @@ func TestSync(t *testing.T) {
defer assert.Nil(t, os.RemoveAll(dir)) defer assert.Nil(t, os.RemoveAll(dir))
stateDB, err := statedb.NewStateDB(dir, statedb.TypeSynchronizer, 32) stateDB, err := statedb.NewStateDB(dir, statedb.TypeSynchronizer, 32)
assert.NoError(t, err)
require.NoError(t, err)
// Init History DB // Init History DB
pass := os.Getenv("POSTGRES_PASS") pass := os.Getenv("POSTGRES_PASS")
@ -452,13 +414,14 @@ func TestSync(t *testing.T) {
ethAddTokens(blocks, client) ethAddTokens(blocks, client)
err = tc.FillBlocksExtra(blocks, &tilCfgExtra) err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
assert.NoError(t, err)
require.NoError(t, err)
tc.FillBlocksL1UserTxsBatchNum(blocks) tc.FillBlocksL1UserTxsBatchNum(blocks)
err = tc.FillBlocksForgedL1UserTxs(blocks) err = tc.FillBlocksForgedL1UserTxs(blocks)
assert.NoError(t, err)
require.NoError(t, err)
// Add block data to the smart contracts // Add block data to the smart contracts
ethAddBlocks(t, blocks, client, clientSetup)
err = client.CtlAddBlocks(blocks)
require.NoError(t, err)
// //
// Sync to synchronize the current state from the test smart contracts, // Sync to synchronize the current state from the test smart contracts,
@ -629,11 +592,12 @@ func TestSync(t *testing.T) {
ethAddTokens(blocks, client) ethAddTokens(blocks, client)
err = tc.FillBlocksExtra(blocks, &tilCfgExtra) err = tc.FillBlocksExtra(blocks, &tilCfgExtra)
assert.NoError(t, err)
require.NoError(t, err)
tc.FillBlocksL1UserTxsBatchNum(blocks) tc.FillBlocksL1UserTxsBatchNum(blocks)
// Add block data to the smart contracts // Add block data to the smart contracts
ethAddBlocks(t, blocks, client, clientSetup)
err = client.CtlAddBlocks(blocks)
require.NoError(t, err)
// First sync detects the reorg and discards 4 blocks // First sync detects the reorg and discards 4 blocks
syncBlock, discards, err = s.Sync2(ctx, nil) syncBlock, discards, err = s.Sync2(ctx, nil)

+ 47
- 0
test/ethclient.go

@ -1719,3 +1719,50 @@ func (c *Client) WDelayerConstants() (*common.WDelayerConstants, error) {
return c.wDelayerConstants, nil return c.wDelayerConstants, nil
} }
// CtlAddBlocks adds block data to the smarts contracts. The added blocks will
// appear as mined. Not thread safe.
func (c *Client) CtlAddBlocks(blocks []common.BlockData) (err error) {
// NOTE: We don't lock because internally we call public functions that
// lock already.
for _, block := range blocks {
nextBlock := c.nextBlock()
rollup := nextBlock.Rollup
auction := nextBlock.Auction
for _, token := range block.Rollup.AddedTokens {
if _, err := c.RollupAddTokenSimple(token.EthAddr, rollup.Vars.FeeAddToken); err != nil {
return err
}
}
for _, tx := range block.Rollup.L1UserTxs {
c.CtlSetAddr(tx.FromEthAddr)
if _, err := c.RollupL1UserTxERC20ETH(tx.FromBJJ, int64(tx.FromIdx), tx.DepositAmount, tx.Amount,
uint32(tx.TokenID), int64(tx.ToIdx)); err != nil {
return err
}
}
c.CtlSetAddr(auction.Vars.BootCoordinator)
for _, batch := range block.Rollup.Batches {
if _, err := c.RollupForgeBatch(&eth.RollupForgeBatchArgs{
NewLastIdx: batch.Batch.LastIdx,
NewStRoot: batch.Batch.StateRoot,
NewExitRoot: batch.Batch.ExitRoot,
L1CoordinatorTxs: batch.L1CoordinatorTxs,
L1CoordinatorTxsAuths: [][]byte{}, // Intentionally empty
L2TxsData: batch.L2Txs,
FeeIdxCoordinator: batch.Batch.FeeIdxsCoordinator,
// Circuit selector
VerifierIdx: 0, // Intentionally empty
L1Batch: batch.L1Batch,
ProofA: [2]*big.Int{}, // Intentionally empty
ProofB: [2][2]*big.Int{}, // Intentionally empty
ProofC: [2]*big.Int{}, // Intentionally empty
}); err != nil {
return err
}
}
// Mine block and sync
c.CtlMineBlock()
}
return nil
}

Loading…
Cancel
Save