diff --git a/cli/node/.gitignore b/cli/node/.gitignore index b77c3b2..47a3b92 100644 --- a/cli/node/.gitignore +++ b/cli/node/.gitignore @@ -1 +1,2 @@ cfg.example.secret.toml +cfg.toml diff --git a/cli/node/cfg.buidler.toml b/cli/node/cfg.buidler.toml index 6d11f7f..6111c28 100644 --- a/cli/node/cfg.buidler.toml +++ b/cli/node/cfg.buidler.toml @@ -39,12 +39,12 @@ TokenHEZ = "0x5D94e3e7aeC542aB0F9129B9a7BAdeb5B3Ca0f77" TokenHEZName = "Hermez Network Token" [Coordinator] -# ForgerAddress = "0x05c23b938a85ab26A36E6314a0D02080E9ca6BeD" # Non-Boot Coordinator +ForgerAddress = "0x05c23b938a85ab26A36E6314a0D02080E9ca6BeD" # Non-Boot Coordinator # ForgerAddressPrivateKey = "0x30f5fddb34cd4166adb2c6003fa6b18f380fd2341376be42cf1c7937004ac7a3" -ForgerAddress = "0xb4124ceb3451635dacedd11767f004d8a28c6ee7" # Boot Coordinator +# ForgerAddress = "0xb4124ceb3451635dacedd11767f004d8a28c6ee7" # Boot Coordinator # ForgerAddressPrivateKey = "0xa8a54b2d8197bc0b19bb8a084031be71835580a01e70a45a13babd16c9bc1563" ConfirmBlocks = 10 -L1BatchTimeoutPerc = 0.4 +L1BatchTimeoutPerc = 0.999 ProofServerPollInterval = "1s" ForgeRetryInterval = "500ms" SyncRetryInterval = "1s" @@ -82,7 +82,7 @@ ReceiptTimeout = "60s" ReceiptLoopInterval = "500ms" CheckLoopInterval = "500ms" Attempts = 4 -AttemptsDelay = "200ms" +AttemptsDelay = "500ms" CallGasLimit = 300000 GasPriceDiv = 100 diff --git a/cli/node/main.go b/cli/node/main.go index a80ccef..3c21331 100644 --- a/cli/node/main.go +++ b/cli/node/main.go @@ -119,10 +119,17 @@ func cmdRun(c *cli.Context) error { // catch ^C to send the stop signal ossig := make(chan os.Signal, 1) signal.Notify(ossig, os.Interrupt) + const forceStopCount = 3 go func() { + n := 0 for sig := range ossig { if sig == os.Interrupt { + log.Info("Received Interrupt Signal") stopCh <- nil + n++ + if n == forceStopCount { + log.Fatalf("Received %v Interrupt Signals", forceStopCount) + } } } }() diff --git a/coordinator/coordinator.go b/coordinator/coordinator.go index 8865cfd..81baa46 100644 --- a/coordinator/coordinator.go +++ b/coordinator/coordinator.go @@ -81,7 +81,7 @@ type Coordinator struct { provers []prover.Client consts synchronizer.SCConsts vars synchronizer.SCVariables - stats *synchronizer.Stats + stats synchronizer.Stats started bool cfg Config @@ -153,15 +153,22 @@ func NewCoordinator(cfg Config, purger: &purger, - // ethClient: ethClient, - msgCh: make(chan interface{}), ctx: ctx, // wg cancel: cancel, } - txManager := NewTxManager(&cfg, ethClient, l2DB, &c) + ctxTimeout, ctxTimeoutCancel := context.WithTimeout(ctx, 1*time.Second) + defer ctxTimeoutCancel() + txManager, err := NewTxManager(ctxTimeout, &cfg, ethClient, l2DB, &c, + scConsts, initSCVars) + if err != nil { + return nil, tracerr.Wrap(err) + } c.txManager = txManager + // Set Eth LastBlockNum to -1 in stats so that stats.Synced() is + // guaranteed to return false before it's updated with a real stats + c.stats.Eth.LastBlock.Num = -1 return &c, nil } @@ -191,8 +198,11 @@ type MsgStopPipeline struct { } // SendMsg is a thread safe method to pass a message to the Coordinator -func (c *Coordinator) SendMsg(msg interface{}) { - c.msgCh <- msg +func (c *Coordinator) SendMsg(ctx context.Context, msg interface{}) { + select { + case c.msgCh <- msg: + case <-ctx.Done(): + } } func (c *Coordinator) syncSCVars(vars synchronizer.SCVariablesPtr) { @@ -207,24 +217,42 @@ func (c *Coordinator) syncSCVars(vars synchronizer.SCVariablesPtr) { } } -func (c *Coordinator) canForge(stats *synchronizer.Stats) bool { +func canForge(auctionConstants *common.AuctionConstants, auctionVars *common.AuctionVariables, + currentSlot *common.Slot, nextSlot *common.Slot, addr ethCommon.Address, blockNum int64) bool { + var slot *common.Slot + if currentSlot.StartBlock <= blockNum && blockNum <= currentSlot.EndBlock { + slot = currentSlot + } else if nextSlot.StartBlock <= blockNum && blockNum <= nextSlot.EndBlock { + slot = nextSlot + } else { + log.Warnw("Coordinator: requested blockNum for canForge is outside slot", + "blockNum", blockNum, "currentSlot", currentSlot, + "nextSlot", nextSlot, + ) + return false + } anyoneForge := false - if !stats.Sync.Auction.CurrentSlot.ForgerCommitment && - c.consts.Auction.RelativeBlock(stats.Eth.LastBlock.Num+1) >= int64(c.vars.Auction.SlotDeadline) { + if !slot.ForgerCommitment && + auctionConstants.RelativeBlock(blockNum) >= int64(auctionVars.SlotDeadline) { log.Debugw("Coordinator: anyone can forge in the current slot (slotDeadline passed)", - "block", stats.Eth.LastBlock.Num+1) + "block", blockNum) anyoneForge = true } - if stats.Sync.Auction.CurrentSlot.Forger == c.cfg.ForgerAddress || anyoneForge { + if slot.Forger == addr || anyoneForge { return true } return false } -func (c *Coordinator) syncStats(ctx context.Context, stats *synchronizer.Stats) error { - c.txManager.SetLastBlock(stats.Eth.LastBlock.Num) +func (c *Coordinator) canForge() bool { + blockNum := c.stats.Eth.LastBlock.Num + 1 + return canForge(&c.consts.Auction, &c.vars.Auction, + &c.stats.Sync.Auction.CurrentSlot, &c.stats.Sync.Auction.NextSlot, + c.cfg.ForgerAddress, blockNum) +} - canForge := c.canForge(stats) +func (c *Coordinator) syncStats(ctx context.Context, stats *synchronizer.Stats) error { + canForge := c.canForge() if c.pipeline == nil { if canForge { log.Infow("Coordinator: forging state begin", "block", @@ -274,22 +302,24 @@ func (c *Coordinator) syncStats(ctx context.Context, stats *synchronizer.Stats) } func (c *Coordinator) handleMsgSyncBlock(ctx context.Context, msg *MsgSyncBlock) error { - c.stats = &msg.Stats + c.stats = msg.Stats c.syncSCVars(msg.Vars) + c.txManager.SetSyncStatsVars(ctx, &msg.Stats, &msg.Vars) if c.pipeline != nil { - c.pipeline.SetSyncStatsVars(&msg.Stats, &msg.Vars) + c.pipeline.SetSyncStatsVars(ctx, &msg.Stats, &msg.Vars) } if !c.stats.Synced() { return nil } - return c.syncStats(ctx, c.stats) + return c.syncStats(ctx, &c.stats) } func (c *Coordinator) handleReorg(ctx context.Context, msg *MsgSyncReorg) error { - c.stats = &msg.Stats + c.stats = msg.Stats c.syncSCVars(msg.Vars) + c.txManager.SetSyncStatsVars(ctx, &msg.Stats, &msg.Vars) if c.pipeline != nil { - c.pipeline.SetSyncStatsVars(&msg.Stats, &msg.Vars) + c.pipeline.SetSyncStatsVars(ctx, &msg.Stats, &msg.Vars) } if common.BatchNum(c.stats.Sync.LastBatch) < c.pipelineBatchNum { // There's been a reorg and the batch from which the pipeline @@ -373,11 +403,11 @@ func (c *Coordinator) Start() { } waitDuration = longWaitDuration case <-time.After(waitDuration): - if c.stats == nil { + if !c.stats.Synced() { waitDuration = longWaitDuration continue } - if err := c.syncStats(c.ctx, c.stats); c.ctx.Err() != nil { + if err := c.syncStats(c.ctx, &c.stats); c.ctx.Err() != nil { continue } else if err != nil { log.Errorw("Coordinator.syncStats", "err", err) diff --git a/coordinator/coordinator_test.go b/coordinator/coordinator_test.go index 496be03..4113967 100644 --- a/coordinator/coordinator_test.go +++ b/coordinator/coordinator_test.go @@ -233,12 +233,17 @@ func TestCoordinatorFlow(t *testing.T) { // Bid for slot 2 and 4 _, err := ethClient.AuctionSetCoordinator(forger, "https://foo.bar") require.NoError(t, err) - _, err = ethClient.AuctionBidSimple(2, big.NewInt(9999)) + bid, ok := new(big.Int).SetString("11000000000000000000", 10) + if !ok { + panic("bad bid") + } + _, err = ethClient.AuctionBidSimple(3, bid) require.NoError(t, err) - _, err = ethClient.AuctionBidSimple(4, big.NewInt(9999)) + _, err = ethClient.AuctionBidSimple(5, bid) require.NoError(t, err) coord.Start() + ctx := context.Background() time.Sleep(1 * time.Second) waitForSlot := func(slot int64) { @@ -259,9 +264,17 @@ func TestCoordinatorFlow(t *testing.T) { stats.Sync.LastBatch = stats.Eth.LastBatch canForge, err := ethClient.AuctionCanForge(forger, blockNum+1) require.NoError(t, err) + var slot common.Slot + slotNum := ethClientSetup.AuctionConstants.SlotNum(blockNum + 1) + slot.StartBlock = ethClientSetup.AuctionConstants.GenesisBlockNum + + (slotNum)*int64(ethClientSetup.AuctionConstants.BlocksPerSlot) + slot.EndBlock = ethClientSetup.AuctionConstants.GenesisBlockNum + + (slotNum+1)*int64(ethClientSetup.AuctionConstants.BlocksPerSlot) if canForge { - stats.Sync.Auction.CurrentSlot.Forger = forger + slot.Forger = forger } + stats.Sync.Auction.CurrentSlot = slot + // Copy stateDB to synchronizer if there was a new batch source := fmt.Sprintf("%v/BatchNum%v", batchBuilderDBPath, stats.Sync.LastBatch) dest := fmt.Sprintf("%v/BatchNum%v", syncDBPath, stats.Sync.LastBatch) @@ -273,7 +286,7 @@ func TestCoordinatorFlow(t *testing.T) { require.NoError(t, err) } } - coord.SendMsg(MsgSyncBlock{ + coord.SendMsg(ctx, MsgSyncBlock{ Stats: stats, }) } @@ -329,7 +342,7 @@ func TestCoordCanForge(t *testing.T) { if !ok { panic("bad bid") } - _, err = ethClient.AuctionBidSimple(2, bid) + _, err = ethClient.AuctionBidSimple(3, bid) require.NoError(t, err) modules2 := newTestModules(t) @@ -343,28 +356,48 @@ func TestCoordCanForge(t *testing.T) { var stats synchronizer.Stats + slots := [4]common.Slot{} + for i := 0; i < 4; i++ { + slots[i].StartBlock = ethClientSetup.AuctionConstants.GenesisBlockNum + + int64(i)*int64(ethClientSetup.AuctionConstants.BlocksPerSlot) + slots[i].EndBlock = ethClientSetup.AuctionConstants.GenesisBlockNum + + int64(i+1)*int64(ethClientSetup.AuctionConstants.BlocksPerSlot) + // Only slot 3 has Coordinator winner, the rest are BootCoordinator + if i == 3 { + slots[i].Forger = forger + } else { + slots[i].Forger = bootForger + } + } + // Slot 0. No bid, so the winner is the boot coordinator stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum stats.Sync.LastBlock = stats.Eth.LastBlock - stats.Sync.Auction.CurrentSlot.Forger = bootForger - assert.Equal(t, false, coord.canForge(&stats)) - assert.Equal(t, true, bootCoord.canForge(&stats)) + stats.Sync.Auction.CurrentSlot = slots[0] + coord.stats = stats + bootCoord.stats = stats + assert.Equal(t, false, coord.canForge()) + assert.Equal(t, true, bootCoord.canForge()) // Slot 0. No bid, and we reach the deadline, so anyone can forge stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum + int64(ethClientSetup.AuctionVariables.SlotDeadline) stats.Sync.LastBlock = stats.Eth.LastBlock - stats.Sync.Auction.CurrentSlot.Forger = bootForger - assert.Equal(t, true, coord.canForge(&stats)) - assert.Equal(t, true, bootCoord.canForge(&stats)) + stats.Sync.Auction.CurrentSlot = slots[0] + coord.stats = stats + bootCoord.stats = stats + assert.Equal(t, true, coord.canForge()) + assert.Equal(t, true, bootCoord.canForge()) - // Slot 1. coordinator bid, so the winner is the coordinator + // Slot 3. coordinator bid, so the winner is the coordinator stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum + - 1*int64(ethClientSetup.AuctionConstants.BlocksPerSlot) + 3*int64(ethClientSetup.AuctionConstants.BlocksPerSlot) stats.Sync.LastBlock = stats.Eth.LastBlock - stats.Sync.Auction.CurrentSlot.Forger = forger - assert.Equal(t, true, coord.canForge(&stats)) - assert.Equal(t, false, bootCoord.canForge(&stats)) + stats.Sync.Auction.CurrentSlot = slots[3] + coord.stats = stats + bootCoord.stats = stats + assert.Equal(t, true, coord.canForge()) + assert.Equal(t, false, bootCoord.canForge()) } func TestCoordHandleMsgSyncBlock(t *testing.T) { @@ -382,49 +415,67 @@ func TestCoordHandleMsgSyncBlock(t *testing.T) { if !ok { panic("bad bid") } - _, err = ethClient.AuctionBidSimple(2, bid) + _, err = ethClient.AuctionBidSimple(3, bid) require.NoError(t, err) + slots := [4]common.Slot{} + for i := 0; i < 4; i++ { + slots[i].StartBlock = ethClientSetup.AuctionConstants.GenesisBlockNum + + int64(i)*int64(ethClientSetup.AuctionConstants.BlocksPerSlot) + slots[i].EndBlock = ethClientSetup.AuctionConstants.GenesisBlockNum + + int64(i+1)*int64(ethClientSetup.AuctionConstants.BlocksPerSlot) + // Only slot 3 has Coordinator winner, the rest are BootCoordinator + if i == 3 { + slots[i].Forger = forger + } else { + slots[i].Forger = bootForger + } + } + var msg MsgSyncBlock - stats := &msg.Stats + coord.stats = msg.Stats ctx := context.Background() // Slot 0. No bid, so the winner is the boot coordinator // pipelineStarted: false -> false - stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum - stats.Sync.LastBlock = stats.Eth.LastBlock - stats.Sync.Auction.CurrentSlot.Forger = bootForger - assert.Equal(t, false, coord.canForge(stats)) + coord.stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum + coord.stats.Sync.LastBlock = coord.stats.Eth.LastBlock + coord.stats.Sync.Auction.CurrentSlot = slots[0] + assert.Equal(t, false, coord.canForge()) + msg.Stats = coord.stats require.NoError(t, coord.handleMsgSyncBlock(ctx, &msg)) assert.Nil(t, coord.pipeline) // Slot 0. No bid, and we reach the deadline, so anyone can forge // pipelineStarted: false -> true - stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum + + coord.stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum + int64(ethClientSetup.AuctionVariables.SlotDeadline) - stats.Sync.LastBlock = stats.Eth.LastBlock - stats.Sync.Auction.CurrentSlot.Forger = bootForger - assert.Equal(t, true, coord.canForge(stats)) + coord.stats.Sync.LastBlock = coord.stats.Eth.LastBlock + coord.stats.Sync.Auction.CurrentSlot = slots[0] + assert.Equal(t, true, coord.canForge()) + msg.Stats = coord.stats require.NoError(t, coord.handleMsgSyncBlock(ctx, &msg)) assert.NotNil(t, coord.pipeline) // Slot 0. No bid, and we reach the deadline, so anyone can forge // pipelineStarted: true -> true - stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum + + coord.stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum + int64(ethClientSetup.AuctionVariables.SlotDeadline) + 1 - stats.Sync.LastBlock = stats.Eth.LastBlock - stats.Sync.Auction.CurrentSlot.Forger = bootForger - assert.Equal(t, true, coord.canForge(stats)) + coord.stats.Sync.LastBlock = coord.stats.Eth.LastBlock + coord.stats.Sync.Auction.CurrentSlot = slots[0] + assert.Equal(t, true, coord.canForge()) + msg.Stats = coord.stats require.NoError(t, coord.handleMsgSyncBlock(ctx, &msg)) assert.NotNil(t, coord.pipeline) - // Slot 0. No bid, so the winner is the boot coordinator + // Slot 1. No bid, so the winner is the boot coordinator // pipelineStarted: true -> false - stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum + + coord.stats.Eth.LastBlock.Num = ethClientSetup.AuctionConstants.GenesisBlockNum + 1*int64(ethClientSetup.AuctionConstants.BlocksPerSlot) - stats.Sync.LastBlock = stats.Eth.LastBlock - stats.Sync.Auction.CurrentSlot.Forger = bootForger - assert.Equal(t, false, coord.canForge(stats)) + coord.stats.Sync.LastBlock = coord.stats.Eth.LastBlock + coord.stats.Sync.Auction.CurrentSlot = slots[1] + assert.Equal(t, false, coord.canForge()) + msg.Stats = coord.stats require.NoError(t, coord.handleMsgSyncBlock(ctx, &msg)) assert.Nil(t, coord.pipeline) } @@ -473,7 +524,7 @@ func TestCoordinatorStress(t *testing.T) { require.NoError(t, err) if blockData != nil { stats := syn.Stats() - coord.SendMsg(MsgSyncBlock{ + coord.SendMsg(ctx, MsgSyncBlock{ Stats: *stats, Batches: blockData.Rollup.Batches, Vars: synchronizer.SCVariablesPtr{ diff --git a/coordinator/pipeline.go b/coordinator/pipeline.go index 60f6417..b514b57 100644 --- a/coordinator/pipeline.go +++ b/coordinator/pipeline.go @@ -71,7 +71,7 @@ func NewPipeline(ctx context.Context, if err := prover.WaitReady(ctx); err != nil { log.Errorw("prover.WaitReady", "err", err) } else { - proversPool.Add(prover) + proversPool.Add(ctx, prover) proversPoolSize++ } } @@ -94,8 +94,11 @@ func NewPipeline(ctx context.Context, } // SetSyncStatsVars is a thread safe method to sets the synchronizer Stats -func (p *Pipeline) SetSyncStatsVars(stats *synchronizer.Stats, vars *synchronizer.SCVariablesPtr) { - p.statsVarsCh <- statsVars{Stats: *stats, Vars: *vars} +func (p *Pipeline) SetSyncStatsVars(ctx context.Context, stats *synchronizer.Stats, vars *synchronizer.SCVariablesPtr) { + select { + case p.statsVarsCh <- statsVars{Stats: *stats, Vars: *vars}: + case <-ctx.Done(): + } } // reset pipeline state @@ -161,7 +164,7 @@ func (p *Pipeline) handleForgeBatch(ctx context.Context, batchNum common.BatchNu } else if err != nil { log.Errorw("sendServerProof", "err", err) batchInfo.ServerProof = nil - p.proversPool.Add(serverProof) + p.proversPool.Add(ctx, serverProof) return nil, err } return batchInfo, nil @@ -202,7 +205,10 @@ func (p *Pipeline) Start(batchNum common.BatchNum, continue } else { p.batchNum = batchNum - batchChSentServerProof <- batchInfo + select { + case batchChSentServerProof <- batchInfo: + case <-p.ctx.Done(): + } } } } @@ -219,16 +225,15 @@ func (p *Pipeline) Start(batchNum common.BatchNum, case batchInfo := <-batchChSentServerProof: err := p.waitServerProof(p.ctx, batchInfo) // We are done with this serverProof, add it back to the pool - p.proversPool.Add(batchInfo.ServerProof) + p.proversPool.Add(p.ctx, batchInfo.ServerProof) batchInfo.ServerProof = nil if p.ctx.Err() != nil { continue - } - if err != nil { + } else if err != nil { log.Errorw("waitServerProof", "err", err) continue } - p.txManager.AddBatch(batchInfo) + p.txManager.AddBatch(p.ctx, batchInfo) } } }() @@ -366,6 +371,7 @@ func (p *Pipeline) forgeBatch(batchNum common.BatchNum) (batchInfo *BatchInfo, e batchInfo.ZKInputs = zkInputs batchInfo.Debug.Status = StatusForged p.cfg.debugBatchStore(batchInfo) + log.Infow("Pipeline: batch forged internally", "batch", batchInfo.BatchNum) return batchInfo, nil } @@ -381,6 +387,7 @@ func (p *Pipeline) waitServerProof(ctx context.Context, batchInfo *BatchInfo) er batchInfo.ForgeBatchArgs = prepareForgeBatchArgs(batchInfo) batchInfo.Debug.Status = StatusProof p.cfg.debugBatchStore(batchInfo) + log.Infow("Pipeline: batch proof calculated", "batch", batchInfo.BatchNum) return nil } diff --git a/coordinator/pipeline_test.go b/coordinator/pipeline_test.go index 65bde7d..f6a1e3d 100644 --- a/coordinator/pipeline_test.go +++ b/coordinator/pipeline_test.go @@ -291,7 +291,9 @@ func TestEthRollupForgeBatch(t *testing.T) { batchInfo.PublicInputs = pubInputs batchInfo.ForgeBatchArgs = prepareForgeBatchArgs(batchInfo) - _, err = client.RollupForgeBatch(batchInfo.ForgeBatchArgs) + auth, err := client.NewAuth() + require.NoError(t, err) + _, err = client.RollupForgeBatch(batchInfo.ForgeBatchArgs, auth) require.NoError(t, err) batchInfo.Proof = proof } diff --git a/coordinator/proverspool.go b/coordinator/proverspool.go index d873c4a..3b7f24f 100644 --- a/coordinator/proverspool.go +++ b/coordinator/proverspool.go @@ -22,8 +22,11 @@ func NewProversPool(maxServerProofs int) *ProversPool { } // Add a prover to the pool -func (p *ProversPool) Add(serverProof prover.Client) { - p.pool <- serverProof +func (p *ProversPool) Add(ctx context.Context, serverProof prover.Client) { + select { + case p.pool <- serverProof: + case <-ctx.Done(): + } } // Get returns the next available prover diff --git a/coordinator/txmanager.go b/coordinator/txmanager.go index 020a79f..5a449c7 100644 --- a/coordinator/txmanager.go +++ b/coordinator/txmanager.go @@ -3,14 +3,18 @@ package coordinator import ( "context" "fmt" - "strings" + "math/big" "time" + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/core/types" "github.com/hermeznetwork/hermez-node/common" "github.com/hermeznetwork/hermez-node/db/l2db" "github.com/hermeznetwork/hermez-node/eth" "github.com/hermeznetwork/hermez-node/log" + "github.com/hermeznetwork/hermez-node/synchronizer" "github.com/hermeznetwork/tracerr" ) @@ -18,61 +22,150 @@ import ( // call to forge, waits for transaction confirmation, and keeps checking them // until a number of confirmed blocks have passed. type TxManager struct { - cfg Config - ethClient eth.ClientInterface - l2DB *l2db.L2DB // Used only to mark forged txs as forged in the L2DB - coord *Coordinator // Used only to send messages to stop the pipeline - batchCh chan *BatchInfo - lastBlockCh chan int64 - queue []*BatchInfo - lastBlock int64 - // lastConfirmedBatch stores the last BatchNum that who's forge call was confirmed - lastConfirmedBatch common.BatchNum + cfg Config + ethClient eth.ClientInterface + l2DB *l2db.L2DB // Used only to mark forged txs as forged in the L2DB + coord *Coordinator // Used only to send messages to stop the pipeline + batchCh chan *BatchInfo + chainID *big.Int + account accounts.Account + consts synchronizer.SCConsts + + stats synchronizer.Stats + vars synchronizer.SCVariables + statsVarsCh chan statsVars + + queue []*BatchInfo + // lastSuccessBatch stores the last BatchNum that who's forge call was confirmed + lastSuccessBatch common.BatchNum + lastPendingBatch common.BatchNum + lastSuccessNonce uint64 + lastPendingNonce uint64 } // NewTxManager creates a new TxManager -func NewTxManager(cfg *Config, ethClient eth.ClientInterface, l2DB *l2db.L2DB, - coord *Coordinator) *TxManager { +func NewTxManager(ctx context.Context, cfg *Config, ethClient eth.ClientInterface, l2DB *l2db.L2DB, + coord *Coordinator, scConsts *synchronizer.SCConsts, initSCVars *synchronizer.SCVariables) (*TxManager, error) { + chainID, err := ethClient.EthChainID() + if err != nil { + return nil, tracerr.Wrap(err) + } + address, err := ethClient.EthAddress() + if err != nil { + return nil, tracerr.Wrap(err) + } + lastSuccessNonce, err := ethClient.EthNonceAt(ctx, *address, nil) + if err != nil { + return nil, err + } + lastPendingNonce, err := ethClient.EthPendingNonceAt(ctx, *address) + if err != nil { + return nil, err + } + if lastSuccessNonce != lastPendingNonce { + return nil, tracerr.Wrap(fmt.Errorf("lastSuccessNonce (%v) != lastPendingNonce (%v)", + lastSuccessNonce, lastPendingNonce)) + } + log.Infow("TxManager started", "nonce", lastSuccessNonce) return &TxManager{ cfg: *cfg, ethClient: ethClient, l2DB: l2DB, coord: coord, batchCh: make(chan *BatchInfo, queueLen), - lastBlockCh: make(chan int64, queueLen), - lastBlock: -1, - } + statsVarsCh: make(chan statsVars, queueLen), + account: accounts.Account{ + Address: *address, + }, + chainID: chainID, + consts: *scConsts, + + vars: *initSCVars, + + lastSuccessNonce: lastSuccessNonce, + lastPendingNonce: lastPendingNonce, + }, nil } // AddBatch is a thread safe method to pass a new batch TxManager to be sent to // the smart contract via the forge call -func (t *TxManager) AddBatch(batchInfo *BatchInfo) { - t.batchCh <- batchInfo +func (t *TxManager) AddBatch(ctx context.Context, batchInfo *BatchInfo) { + select { + case t.batchCh <- batchInfo: + case <-ctx.Done(): + } +} + +// SetSyncStatsVars is a thread safe method to sets the synchronizer Stats +func (t *TxManager) SetSyncStatsVars(ctx context.Context, stats *synchronizer.Stats, vars *synchronizer.SCVariablesPtr) { + select { + case t.statsVarsCh <- statsVars{Stats: *stats, Vars: *vars}: + case <-ctx.Done(): + } } -// SetLastBlock is a thread safe method to pass the lastBlock to the TxManager -func (t *TxManager) SetLastBlock(lastBlock int64) { - t.lastBlockCh <- lastBlock +func (t *TxManager) syncSCVars(vars synchronizer.SCVariablesPtr) { + if vars.Rollup != nil { + t.vars.Rollup = *vars.Rollup + } + if vars.Auction != nil { + t.vars.Auction = *vars.Auction + } + if vars.WDelayer != nil { + t.vars.WDelayer = *vars.WDelayer + } +} + +// NewAuth generates a new auth object for an ethereum transaction +func (t *TxManager) NewAuth(ctx context.Context) (*bind.TransactOpts, error) { + gasPrice, err := t.ethClient.EthSuggestGasPrice(ctx) + if err != nil { + return nil, tracerr.Wrap(err) + } + inc := new(big.Int).Set(gasPrice) + const gasPriceDiv = 100 + inc.Div(inc, new(big.Int).SetUint64(gasPriceDiv)) + gasPrice.Add(gasPrice, inc) + // log.Debugw("TxManager: transaction metadata", "gasPrice", gasPrice) + + auth, err := bind.NewKeyStoreTransactorWithChainID(t.ethClient.EthKeyStore(), t.account, t.chainID) + if err != nil { + return nil, tracerr.Wrap(err) + } + auth.Value = big.NewInt(0) // in wei + // TODO: Calculate GasLimit based on the contents of the ForgeBatchArgs + auth.GasLimit = 1000000 + auth.GasPrice = gasPrice + auth.Nonce = nil + + return auth, nil } -func (t *TxManager) callRollupForgeBatch(ctx context.Context, batchInfo *BatchInfo) error { +func (t *TxManager) sendRollupForgeBatch(ctx context.Context, batchInfo *BatchInfo) error { + // TODO: Check if we can forge in the next blockNum, abort if we can't batchInfo.Debug.Status = StatusSent - batchInfo.Debug.SendBlockNum = t.lastBlock + 1 + batchInfo.Debug.SendBlockNum = t.stats.Eth.LastBlock.Num + 1 batchInfo.Debug.SendTimestamp = time.Now() batchInfo.Debug.StartToSendDelay = batchInfo.Debug.SendTimestamp.Sub( batchInfo.Debug.StartTimestamp).Seconds() var ethTx *types.Transaction var err error + auth, err := t.NewAuth(ctx) + if err != nil { + return tracerr.Wrap(err) + } + auth.Nonce = big.NewInt(int64(t.lastPendingNonce)) + t.lastPendingNonce++ for attempt := 0; attempt < t.cfg.EthClientAttempts; attempt++ { - ethTx, err = t.ethClient.RollupForgeBatch(batchInfo.ForgeBatchArgs) + ethTx, err = t.ethClient.RollupForgeBatch(batchInfo.ForgeBatchArgs, auth) if err != nil { - if strings.Contains(err.Error(), common.AuctionErrMsgCannotForge) { - log.Debugw("TxManager ethClient.RollupForgeBatch", "err", err, - "block", t.lastBlock+1) - return tracerr.Wrap(err) - } + // if strings.Contains(err.Error(), common.AuctionErrMsgCannotForge) { + // log.Errorw("TxManager ethClient.RollupForgeBatch", "err", err, + // "block", t.stats.Eth.LastBlock.Num+1) + // return tracerr.Wrap(err) + // } log.Errorw("TxManager ethClient.RollupForgeBatch", - "attempt", attempt, "err", err, "block", t.lastBlock+1, + "attempt", attempt, "err", err, "block", t.stats.Eth.LastBlock.Num+1, "batchNum", batchInfo.BatchNum) } else { break @@ -89,12 +182,15 @@ func (t *TxManager) callRollupForgeBatch(ctx context.Context, batchInfo *BatchIn batchInfo.EthTx = ethTx log.Infow("TxManager ethClient.RollupForgeBatch", "batch", batchInfo.BatchNum, "tx", ethTx.Hash().Hex()) t.cfg.debugBatchStore(batchInfo) + t.lastPendingBatch = batchInfo.BatchNum if err := t.l2DB.DoneForging(common.TxIDsFromL2Txs(batchInfo.L2Txs), batchInfo.BatchNum); err != nil { return tracerr.Wrap(err) } return nil } +// checkEthTransactionReceipt takes the txHash from the BatchInfo and stores +// the corresponding receipt if found func (t *TxManager) checkEthTransactionReceipt(ctx context.Context, batchInfo *BatchInfo) error { txHash := batchInfo.EthTx.Hash() var receipt *types.Receipt @@ -103,8 +199,10 @@ func (t *TxManager) checkEthTransactionReceipt(ctx context.Context, batchInfo *B receipt, err = t.ethClient.EthTransactionReceipt(ctx, txHash) if ctx.Err() != nil { continue - } - if err != nil { + } else if tracerr.Unwrap(err) == ethereum.NotFound { + err = nil + break + } else if err != nil { log.Errorw("TxManager ethClient.EthTransactionReceipt", "attempt", attempt, "err", err) } else { @@ -124,24 +222,28 @@ func (t *TxManager) checkEthTransactionReceipt(ctx context.Context, batchInfo *B return nil } -func (t *TxManager) handleReceipt(batchInfo *BatchInfo) (*int64, error) { +func (t *TxManager) handleReceipt(ctx context.Context, batchInfo *BatchInfo) (*int64, error) { receipt := batchInfo.Receipt if receipt != nil { if receipt.Status == types.ReceiptStatusFailed { batchInfo.Debug.Status = StatusFailed t.cfg.debugBatchStore(batchInfo) - log.Errorw("TxManager receipt status is failed", "receipt", receipt) - return nil, tracerr.Wrap(fmt.Errorf("ethereum transaction receipt statis is failed")) + _, err := t.ethClient.EthCall(ctx, batchInfo.EthTx, receipt.BlockNumber) + log.Warnw("TxManager receipt status is failed", "tx", receipt.TxHash.Hex(), + "batch", batchInfo.BatchNum, "block", receipt.BlockNumber.Int64(), + "err", err) + return nil, tracerr.Wrap(fmt.Errorf( + "ethereum transaction receipt status is failed: %w", err)) } else if receipt.Status == types.ReceiptStatusSuccessful { batchInfo.Debug.Status = StatusMined batchInfo.Debug.MineBlockNum = receipt.BlockNumber.Int64() batchInfo.Debug.StartToMineBlocksDelay = batchInfo.Debug.MineBlockNum - batchInfo.Debug.StartBlockNum t.cfg.debugBatchStore(batchInfo) - if batchInfo.BatchNum > t.lastConfirmedBatch { - t.lastConfirmedBatch = batchInfo.BatchNum + if batchInfo.BatchNum > t.lastSuccessBatch { + t.lastSuccessBatch = batchInfo.BatchNum } - confirm := t.lastBlock - receipt.BlockNumber.Int64() + confirm := t.stats.Eth.LastBlock.Num - receipt.BlockNumber.Int64() return &confirm, nil } } @@ -153,25 +255,41 @@ func (t *TxManager) Run(ctx context.Context) { next := 0 waitDuration := longWaitDuration + var statsVars statsVars + select { + case statsVars = <-t.statsVarsCh: + case <-ctx.Done(): + } + t.stats = statsVars.Stats + t.syncSCVars(statsVars.Vars) + log.Infow("TxManager: received initial statsVars", + "block", t.stats.Eth.LastBlock.Num, "batch", t.stats.Eth.LastBatch) + for { select { case <-ctx.Done(): log.Info("TxManager done") return - case lastBlock := <-t.lastBlockCh: - t.lastBlock = lastBlock + case statsVars := <-t.statsVarsCh: + t.stats = statsVars.Stats + t.syncSCVars(statsVars.Vars) case batchInfo := <-t.batchCh: - if err := t.callRollupForgeBatch(ctx, batchInfo); ctx.Err() != nil { + if err := t.sendRollupForgeBatch(ctx, batchInfo); ctx.Err() != nil { continue } else if err != nil { - t.coord.SendMsg(MsgStopPipeline{Reason: fmt.Sprintf("forgeBatch call: %v", err)}) + // If we reach here it's because our ethNode has + // been unable to send the transaction to + // ethereum. This could be due to the ethNode + // failure, or an invalid transaction (that + // can't be mined) + t.coord.SendMsg(ctx, MsgStopPipeline{Reason: fmt.Sprintf("forgeBatch send: %v", err)}) continue } - log.Debugf("ethClient ForgeCall sent, batchNum: %d", batchInfo.BatchNum) t.queue = append(t.queue, batchInfo) waitDuration = t.cfg.TxManagerCheckInterval case <-time.After(waitDuration): if len(t.queue) == 0 { + waitDuration = longWaitDuration continue } current := next @@ -180,23 +298,33 @@ func (t *TxManager) Run(ctx context.Context) { if err := t.checkEthTransactionReceipt(ctx, batchInfo); ctx.Err() != nil { continue } else if err != nil { //nolint:staticcheck - // We can't get the receipt for the - // transaction, so we can't confirm if it was - // mined - t.coord.SendMsg(MsgStopPipeline{Reason: fmt.Sprintf("forgeBatch receipt: %v", err)}) + // Our ethNode is giving an error different + // than "not found" when getting the receipt + // for the transaction, so we can't figure out + // if it was not mined, mined and succesfull or + // mined and failed. This could be due to the + // ethNode failure. + t.coord.SendMsg(ctx, MsgStopPipeline{Reason: fmt.Sprintf("forgeBatch receipt: %v", err)}) } - confirm, err := t.handleReceipt(batchInfo) - if err != nil { //nolint:staticcheck + confirm, err := t.handleReceipt(ctx, batchInfo) + if ctx.Err() != nil { + continue + } else if err != nil { //nolint:staticcheck // Transaction was rejected - t.coord.SendMsg(MsgStopPipeline{Reason: fmt.Sprintf("forgeBatch reject: %v", err)}) + t.queue = append(t.queue[:current], t.queue[current+1:]...) + if len(t.queue) == 0 { + next = 0 + } else { + next = current % len(t.queue) + } + t.coord.SendMsg(ctx, MsgStopPipeline{Reason: fmt.Sprintf("forgeBatch reject: %v", err)}) } if confirm != nil && *confirm >= t.cfg.ConfirmBlocks { log.Debugw("TxManager tx for RollupForgeBatch confirmed", "batch", batchInfo.BatchNum) t.queue = append(t.queue[:current], t.queue[current+1:]...) if len(t.queue) == 0 { - waitDuration = longWaitDuration next = 0 } else { next = current % len(t.queue) @@ -205,3 +333,11 @@ func (t *TxManager) Run(ctx context.Context) { } } } + +// nolint reason: this function will be used in the future +//nolint:unused +func (t *TxManager) canForge(stats *synchronizer.Stats, blockNum int64) bool { + return canForge(&t.consts.Auction, &t.vars.Auction, + &stats.Sync.Auction.CurrentSlot, &stats.Sync.Auction.NextSlot, + t.cfg.ForgerAddress, blockNum) +} diff --git a/db/kvdb/kvdb.go b/db/kvdb/kvdb.go index cc95089..b136f0e 100644 --- a/db/kvdb/kvdb.go +++ b/db/kvdb/kvdb.go @@ -322,7 +322,6 @@ func (kvdb *KVDB) SetCurrentIdx(idx common.Idx) error { func (kvdb *KVDB) MakeCheckpoint() error { // advance currentBatch kvdb.CurrentBatch++ - log.Debugw("Making KVDB checkpoint", "batch", kvdb.CurrentBatch) checkpointPath := path.Join(kvdb.path, fmt.Sprintf("%s%d", PathBatchNum, kvdb.CurrentBatch)) diff --git a/db/statedb/statedb.go b/db/statedb/statedb.go index d5410e9..8782ff9 100644 --- a/db/statedb/statedb.go +++ b/db/statedb/statedb.go @@ -101,7 +101,7 @@ func NewStateDB(pathDB string, keep int, typ TypeStateDB, nLevels int) (*StateDB // Internally this advances & stores the current BatchNum, and then stores a // Checkpoint of the current state of the StateDB. func (s *StateDB) MakeCheckpoint() error { - log.Debugw("Making StateDB checkpoint", "batch", s.CurrentBatch()+1) + log.Debugw("Making StateDB checkpoint", "batch", s.CurrentBatch()+1, "type", s.Typ) return s.db.MakeCheckpoint() } diff --git a/eth/ethereum.go b/eth/ethereum.go index 09de3ca..d1d798a 100644 --- a/eth/ethereum.go +++ b/eth/ethereum.go @@ -6,6 +6,7 @@ import ( "math/big" "time" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/abi/bind" ethKeystore "github.com/ethereum/go-ethereum/accounts/keystore" @@ -35,6 +36,12 @@ type EthereumInterface interface { EthERC20Consts(ethCommon.Address) (*ERC20Consts, error) EthChainID() (*big.Int, error) + + EthPendingNonceAt(ctx context.Context, account ethCommon.Address) (uint64, error) + EthNonceAt(ctx context.Context, account ethCommon.Address, blockNumber *big.Int) (uint64, error) + EthSuggestGasPrice(ctx context.Context) (*big.Int, error) + EthKeyStore() *ethKeystore.KeyStore + EthCall(ctx context.Context, tx *types.Transaction, blockNum *big.Int) ([]byte, error) } var ( @@ -118,6 +125,43 @@ func (c *EthereumClient) EthAddress() (*ethCommon.Address, error) { return &c.account.Address, nil } +// EthSuggestGasPrice retrieves the currently suggested gas price to allow a +// timely execution of a transaction. +func (c *EthereumClient) EthSuggestGasPrice(ctx context.Context) (*big.Int, error) { + return c.client.SuggestGasPrice(ctx) +} + +// EthKeyStore returns the keystore in the EthereumClient +func (c *EthereumClient) EthKeyStore() *ethKeystore.KeyStore { + return c.ks +} + +// NewAuth builds a new auth object to make a transaction +func (c *EthereumClient) NewAuth() (*bind.TransactOpts, error) { + if c.account == nil { + return nil, tracerr.Wrap(ErrAccountNil) + } + + gasPrice, err := c.client.SuggestGasPrice(context.Background()) + if err != nil { + return nil, tracerr.Wrap(err) + } + inc := new(big.Int).Set(gasPrice) + inc.Div(inc, new(big.Int).SetUint64(c.config.GasPriceDiv)) + gasPrice.Add(gasPrice, inc) + log.Debugw("Transaction metadata", "gasPrice", gasPrice) + + auth, err := bind.NewKeyStoreTransactorWithChainID(c.ks, *c.account, c.chainID) + if err != nil { + return nil, tracerr.Wrap(err) + } + auth.Value = big.NewInt(0) // in wei + auth.GasLimit = c.config.CallGasLimit + auth.GasPrice = gasPrice + + return auth, nil +} + // CallAuth performs a Smart Contract method call that requires authorization. // This call requires a valid account with Ether that can be spend during the // call. @@ -250,3 +294,35 @@ func newCallOpts() *bind.CallOpts { From: ethCommon.HexToAddress("0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"), } } + +// EthPendingNonceAt returns the account nonce of the given account in the pending +// state. This is the nonce that should be used for the next transaction. +func (c *EthereumClient) EthPendingNonceAt(ctx context.Context, + account ethCommon.Address) (uint64, error) { + return c.client.PendingNonceAt(ctx, account) +} + +// EthNonceAt returns the account nonce of the given account. The block number can +// be nil, in which case the nonce is taken from the latest known block. +func (c *EthereumClient) EthNonceAt(ctx context.Context, + account ethCommon.Address, blockNumber *big.Int) (uint64, error) { + return c.client.NonceAt(ctx, account, blockNumber) +} + +// EthCall runs the transaction as a call (without paying) in the local node at +// blockNum. +func (c *EthereumClient) EthCall(ctx context.Context, tx *types.Transaction, + blockNum *big.Int) ([]byte, error) { + if c.account == nil { + return nil, tracerr.Wrap(ErrAccountNil) + } + msg := ethereum.CallMsg{ + From: c.account.Address, + To: tx.To(), + Gas: tx.Gas(), + GasPrice: tx.GasPrice(), + Value: tx.Value(), + Data: tx.Data(), + } + return c.client.CallContract(ctx, msg, blockNum) +} diff --git a/eth/rollup.go b/eth/rollup.go index 1fedc68..b94c59a 100644 --- a/eth/rollup.go +++ b/eth/rollup.go @@ -242,7 +242,7 @@ type RollupInterface interface { // Public Functions - RollupForgeBatch(*RollupForgeBatchArgs) (*types.Transaction, error) + RollupForgeBatch(*RollupForgeBatchArgs, *bind.TransactOpts) (*types.Transaction, error) RollupAddToken(tokenAddress ethCommon.Address, feeAddToken, deadline *big.Int) (*types.Transaction, error) RollupWithdrawMerkleProof(babyPubKey babyjub.PublicKeyComp, tokenID uint32, numExitRoot, idx int64, amount *big.Int, siblings []*big.Int, instantWithdraw bool) (*types.Transaction, error) @@ -323,70 +323,77 @@ func NewRollupClient(client *EthereumClient, address ethCommon.Address, tokenHEZ } // RollupForgeBatch is the interface to call the smart contract function -func (c *RollupClient) RollupForgeBatch(args *RollupForgeBatchArgs) (tx *types.Transaction, err error) { - if tx, err = c.client.CallAuth( - 1000000, //nolint:gomnd - func(ec *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) { - nLevels := c.consts.Verifiers[args.VerifierIdx].NLevels - lenBytes := nLevels / 8 //nolint:gomnd - newLastIdx := big.NewInt(int64(args.NewLastIdx)) - // L1CoordinatorBytes - var l1CoordinatorBytes []byte - for i := 0; i < len(args.L1CoordinatorTxs); i++ { - l1 := args.L1CoordinatorTxs[i] - bytesl1, err := l1.BytesCoordinatorTx(args.L1CoordinatorTxsAuths[i]) - if err != nil { - return nil, tracerr.Wrap(err) - } - l1CoordinatorBytes = append(l1CoordinatorBytes, bytesl1[:]...) - } - // L1L2TxData - var l1l2TxData []byte - for i := 0; i < len(args.L1UserTxs); i++ { - l1User := args.L1UserTxs[i] - bytesl1User, err := l1User.BytesDataAvailability(uint32(nLevels)) - if err != nil { - return nil, tracerr.Wrap(err) - } - l1l2TxData = append(l1l2TxData, bytesl1User[:]...) - } - for i := 0; i < len(args.L1CoordinatorTxs); i++ { - l1Coord := args.L1CoordinatorTxs[i] - bytesl1Coord, err := l1Coord.BytesDataAvailability(uint32(nLevels)) - if err != nil { - return nil, tracerr.Wrap(err) - } - l1l2TxData = append(l1l2TxData, bytesl1Coord[:]...) - } - for i := 0; i < len(args.L2TxsData); i++ { - l2 := args.L2TxsData[i] - bytesl2, err := l2.BytesDataAvailability(uint32(nLevels)) - if err != nil { - return nil, tracerr.Wrap(err) - } - l1l2TxData = append(l1l2TxData, bytesl2[:]...) - } - // FeeIdxCoordinator - var feeIdxCoordinator []byte - if len(args.FeeIdxCoordinator) > common.RollupConstMaxFeeIdxCoordinator { - return nil, tracerr.Wrap(fmt.Errorf("len(args.FeeIdxCoordinator) > %v", - common.RollupConstMaxFeeIdxCoordinator)) - } - for i := 0; i < common.RollupConstMaxFeeIdxCoordinator; i++ { - feeIdx := common.Idx(0) - if i < len(args.FeeIdxCoordinator) { - feeIdx = args.FeeIdxCoordinator[i] - } - bytesFeeIdx, err := feeIdx.Bytes() - if err != nil { - return nil, tracerr.Wrap(err) - } - feeIdxCoordinator = append(feeIdxCoordinator, bytesFeeIdx[len(bytesFeeIdx)-int(lenBytes):]...) - } - return c.hermez.ForgeBatch(auth, newLastIdx, args.NewStRoot, args.NewExitRoot, l1CoordinatorBytes, l1l2TxData, feeIdxCoordinator, args.VerifierIdx, args.L1Batch, args.ProofA, args.ProofB, args.ProofC) - }, - ); err != nil { - return nil, tracerr.Wrap(fmt.Errorf("Failed forge batch: %w", err)) +func (c *RollupClient) RollupForgeBatch(args *RollupForgeBatchArgs, auth *bind.TransactOpts) (tx *types.Transaction, err error) { + if auth == nil { + auth, err := c.client.NewAuth() + if err != nil { + return nil, err + } + auth.GasLimit = 1000000 + } + + nLevels := c.consts.Verifiers[args.VerifierIdx].NLevels + lenBytes := nLevels / 8 //nolint:gomnd + newLastIdx := big.NewInt(int64(args.NewLastIdx)) + // L1CoordinatorBytes + var l1CoordinatorBytes []byte + for i := 0; i < len(args.L1CoordinatorTxs); i++ { + l1 := args.L1CoordinatorTxs[i] + bytesl1, err := l1.BytesCoordinatorTx(args.L1CoordinatorTxsAuths[i]) + if err != nil { + return nil, tracerr.Wrap(err) + } + l1CoordinatorBytes = append(l1CoordinatorBytes, bytesl1[:]...) + } + // L1L2TxData + var l1l2TxData []byte + for i := 0; i < len(args.L1UserTxs); i++ { + l1User := args.L1UserTxs[i] + bytesl1User, err := l1User.BytesDataAvailability(uint32(nLevels)) + if err != nil { + return nil, tracerr.Wrap(err) + } + l1l2TxData = append(l1l2TxData, bytesl1User[:]...) + } + for i := 0; i < len(args.L1CoordinatorTxs); i++ { + l1Coord := args.L1CoordinatorTxs[i] + bytesl1Coord, err := l1Coord.BytesDataAvailability(uint32(nLevels)) + if err != nil { + return nil, tracerr.Wrap(err) + } + l1l2TxData = append(l1l2TxData, bytesl1Coord[:]...) + } + for i := 0; i < len(args.L2TxsData); i++ { + l2 := args.L2TxsData[i] + bytesl2, err := l2.BytesDataAvailability(uint32(nLevels)) + if err != nil { + return nil, tracerr.Wrap(err) + } + l1l2TxData = append(l1l2TxData, bytesl2[:]...) + } + // FeeIdxCoordinator + var feeIdxCoordinator []byte + if len(args.FeeIdxCoordinator) > common.RollupConstMaxFeeIdxCoordinator { + return nil, tracerr.Wrap(fmt.Errorf("len(args.FeeIdxCoordinator) > %v", + common.RollupConstMaxFeeIdxCoordinator)) + } + for i := 0; i < common.RollupConstMaxFeeIdxCoordinator; i++ { + feeIdx := common.Idx(0) + if i < len(args.FeeIdxCoordinator) { + feeIdx = args.FeeIdxCoordinator[i] + } + bytesFeeIdx, err := feeIdx.Bytes() + if err != nil { + return nil, tracerr.Wrap(err) + } + feeIdxCoordinator = append(feeIdxCoordinator, + bytesFeeIdx[len(bytesFeeIdx)-int(lenBytes):]...) + } + tx, err = c.hermez.ForgeBatch(auth, newLastIdx, args.NewStRoot, args.NewExitRoot, + l1CoordinatorBytes, l1l2TxData, feeIdxCoordinator, args.VerifierIdx, args.L1Batch, + args.ProofA, args.ProofB, args.ProofC) + if err != nil { + return nil, tracerr.Wrap(fmt.Errorf("Failed Hermez.ForgeBatch: %w", err)) } return tx, nil } diff --git a/eth/rollup_test.go b/eth/rollup_test.go index f9b011c..b36e27a 100644 --- a/eth/rollup_test.go +++ b/eth/rollup_test.go @@ -169,7 +169,9 @@ func TestRollupForgeBatch(t *testing.T) { args.ProofC[1] = big.NewInt(0) argsForge = args - _, err = rollupClient.RollupForgeBatch(argsForge) + auth, err := rollupClient.client.NewAuth() + require.NoError(t, err) + _, err = rollupClient.RollupForgeBatch(argsForge, auth) require.NoError(t, err) currentBlockNum, err = rollupClient.client.EthLastBlock() @@ -818,7 +820,9 @@ func TestRollupL1UserTxERC20PermitForceExit(t *testing.T) { func TestRollupForgeBatch2(t *testing.T) { // Forge Batch 2 - _, err := rollupClient.RollupForgeBatch(argsForge) + auth, err := rollupClient.client.NewAuth() + require.NoError(t, err) + _, err = rollupClient.RollupForgeBatch(argsForge, auth) require.NoError(t, err) currentBlockNum, err := rollupClient.client.EthLastBlock() require.NoError(t, err) @@ -871,7 +875,9 @@ func TestRollupForgeBatch2(t *testing.T) { argsForge = args - _, err = rollupClient.RollupForgeBatch(argsForge) + auth, err = rollupClient.client.NewAuth() + require.NoError(t, err) + _, err = rollupClient.RollupForgeBatch(argsForge, auth) require.NoError(t, err) currentBlockNum, err = rollupClient.client.EthLastBlock() diff --git a/go.mod b/go.mod index 9738860..c3488bd 100644 --- a/go.mod +++ b/go.mod @@ -4,14 +4,13 @@ go 1.14 require ( github.com/BurntSushi/toml v0.3.1 - github.com/btcsuite/btcd v0.21.0-beta // indirect github.com/dghubble/sling v1.3.0 github.com/ethereum/go-ethereum v1.9.25 github.com/getkin/kin-openapi v0.22.0 github.com/gin-contrib/cors v1.3.1 github.com/gin-gonic/gin v1.5.0 github.com/gobuffalo/packr/v2 v2.8.1 - github.com/hermeznetwork/tracerr v0.3.1-0.20201126162137-de9930d0cf29 + github.com/hermeznetwork/tracerr v0.3.1-0.20210120162744-5da60b576169 github.com/iden3/go-iden3-crypto v0.0.6-0.20201221160344-58e589b6eb4c github.com/iden3/go-merkletree v0.0.0-20210105105053-5a669a1b3958 github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a @@ -22,18 +21,12 @@ require ( github.com/miguelmota/go-ethereum-hdwallet v0.0.0-20200123000308-a60dcd172b4c github.com/mitchellh/copystructure v1.0.0 github.com/mitchellh/mapstructure v1.3.0 - github.com/rogpeppe/go-internal v1.6.1 // indirect github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351 github.com/russross/meddler v1.0.0 github.com/stretchr/testify v1.6.1 - github.com/ugorji/go v1.1.8 // indirect github.com/urfave/cli/v2 v2.2.0 - go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.16.0 golang.org/x/crypto v0.0.0-20201217014255-9d1352758620 golang.org/x/net v0.0.0-20200822124328-c89045814202 - golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e // indirect - golang.org/x/tools v0.0.0-20200914163123-ea50a3c84940 // indirect gopkg.in/go-playground/validator.v9 v9.29.1 - honnef.co/go/tools v0.0.1-2020.1.5 // indirect ) diff --git a/go.sum b/go.sum index d93f4b6..0dc8230 100644 --- a/go.sum +++ b/go.sum @@ -71,19 +71,12 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3 h1:A/EVblehb75cUgXA5njHPn0kLAsykn6mJGz7rnmW5W0= github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= -github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= -github.com/btcsuite/btcd v0.21.0-beta h1:At9hIZdJW0s9E/fAz28nrz6AmcNlSVucCH796ZteX1M= -github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= -github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts= -github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= -github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= -github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= @@ -137,7 +130,6 @@ github.com/dchest/blake512 v1.0.0 h1:oDFEQFIqFSeuA34xLtXZ/rWxCXdSjirjzPhey5EUvmA github.com/dchest/blake512 v1.0.0/go.mod h1:FV1x7xPPLWukZlpDpWQ88rF/SFwZ5qbskrzhLMB92JI= github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea h1:j4317fAZh7X6GqbFowYdYdI0L9bwxL07jyPZIdepyZ0= github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= -github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dghubble/sling v1.3.0 h1:pZHjCJq4zJvc6qVQ5wN1jo5oNZlNE0+8T/h0XeXBUKU= github.com/dghubble/sling v1.3.0/go.mod h1:XXShWaBWKzNLhu2OxikSNFrlsvowtz4kyRuXUG7oQKY= @@ -180,7 +172,6 @@ github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+ github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -250,7 +241,6 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -260,7 +250,6 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= @@ -329,11 +318,10 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hermeznetwork/tracerr v0.3.1-0.20201126162137-de9930d0cf29 h1:dlXz/aVJfCh/wvF6jjsrl/lqHJbOigQLG6vFF5zGuNs= -github.com/hermeznetwork/tracerr v0.3.1-0.20201126162137-de9930d0cf29/go.mod h1:nsWC1+tc4qUEbUGRv4DcPJJTjLsedlPajlFmpJoohK4= +github.com/hermeznetwork/tracerr v0.3.1-0.20210120162744-5da60b576169 h1:I7zgVVlOgf+26yrrKKY9UT+9f73qqlNBGX6C9MPXnk4= +github.com/hermeznetwork/tracerr v0.3.1-0.20210120162744-5da60b576169/go.mod h1:nsWC1+tc4qUEbUGRv4DcPJJTjLsedlPajlFmpJoohK4= github.com/holiman/uint256 v1.1.1 h1:4JywC80b+/hSfljFlEBLHrrh+CIONLDz9NuFl0af4Mw= github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag= @@ -361,7 +349,6 @@ github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a h1:zPPuIq2jAWWPTrGt70eK/BSch+gFAGrNzecsoENgu2o= github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -429,7 +416,6 @@ github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2 github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.0 h1:v2XXALHHh6zHfYTJ+cSkwtyffnaOyR1MXaA91mTrb8o= github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -503,15 +489,12 @@ github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1 github.com/olekukonko/tablewriter v0.0.2 h1:sq53g+DWf0J6/ceFUHpQ0nAEb6WgM++fq16MZ91cS6o= github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= @@ -587,8 +570,6 @@ github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.5.2 h1:qLvObTrvO/XRCqmkKxUlOBc48bI3efyDuAZe25QiF0w= github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= @@ -650,7 +631,6 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/syndtr/goleveldb v0.0.0-20180621010148-0d5a0ceb10cf/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= -github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca h1:Ld/zXl5t4+D69SiV4JoN7kkfvJdOWlPpfxrzxpLMoUk= github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= @@ -662,16 +642,12 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1 github.com/tyler-smith/go-bip39 v0.0.0-20180618194314-52158e4697b8/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef h1:wHSqTBrZW24CsNJDfeh9Ex6Pm0Rcpc7qrgKBiL44vF4= github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= -github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go v1.1.8 h1:/D9x7IRpfMHDlizVOgxrag5Fh+/NY+LtI8bsr+AswRA= -github.com/ugorji/go v1.1.8/go.mod h1:0lNM99SwWUIRhCXnigEMClngXBk/EmpTXa7mgiewYWA= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8 h1:3SVOIvH7Ae1KRYyQWRjXWJEA9sS/c/pjvH++55Gr648= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/ugorji/go/codec v1.1.8 h1:4dryPvxMP9OtkjIbuNeK2nb27M38XMHLGlfNSNph/5s= -github.com/ugorji/go/codec v1.1.8/go.mod h1:X00B19HDtwvKbQY2DcYjvZxKQp8mzrJoQ6EgoIY/D2E= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= @@ -697,11 +673,8 @@ github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmv github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= -github.com/ztrue/tracerr v0.3.0 h1:lDi6EgEYhPYPnKcjsYzmWw4EkFEoA/gfe+I9Y5f+h6Y= -github.com/ztrue/tracerr v0.3.0/go.mod h1:qEalzze4VN9O8tnhBXScfCrmoJo10o8TN5ciKjm6Mww= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= @@ -710,22 +683,16 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= @@ -743,10 +710,7 @@ golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201217014255-9d1352758620 h1:3wPMTskHO3+O6jqTEXyFcsnuxMQOqYSaHsDxcbUXpqA= golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= @@ -773,9 +737,6 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -812,10 +773,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -850,19 +808,14 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8 h1:AvbQYmiaaaza3cW3QXRyPo5kYgpFIzOAfeAAN7m3qQ4= golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e h1:AyodaIpKjppX+cBfTASF2E1US3H2JFBj920Ot3rtDjs= -golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -889,17 +842,13 @@ golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200308013534-11ec41452d41 h1:9Di9iYgOt9ThCipBxChBVhgNipDoE5mxO84rQV7D0FE= golang.org/x/tools v0.0.0-20200308013534-11ec41452d41/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200914163123-ea50a3c84940 h1:151ExL+g/k/wnhOqV+O1OliaTi0FR2UxQEEcpAhzzw8= -golang.org/x/tools v0.0.0-20200914163123-ea50a3c84940/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -936,14 +885,12 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fatih/set.v0 v0.2.1/go.mod h1:5eLWEndGL4zGGemXWrKuts+wTJR0y+w+auqUJZbmyBg= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= @@ -976,7 +923,6 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -988,7 +934,5 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.5 h1:nI5egYTGJakVyOryqLs1cQO5dO0ksin5XXs2pspk75k= -honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/node/node.go b/node/node.go index 7bc8db7..b902c54 100644 --- a/node/node.go +++ b/node/node.go @@ -429,10 +429,10 @@ func (a *NodeAPI) Run(ctx context.Context) error { return nil } -func (n *Node) handleNewBlock(stats *synchronizer.Stats, vars synchronizer.SCVariablesPtr, +func (n *Node) handleNewBlock(ctx context.Context, stats *synchronizer.Stats, vars synchronizer.SCVariablesPtr, batches []common.BatchData) { if n.mode == ModeCoordinator { - n.coord.SendMsg(coordinator.MsgSyncBlock{ + n.coord.SendMsg(ctx, coordinator.MsgSyncBlock{ Stats: *stats, Vars: vars, Batches: batches, @@ -461,9 +461,9 @@ func (n *Node) handleNewBlock(stats *synchronizer.Stats, vars synchronizer.SCVar } } -func (n *Node) handleReorg(stats *synchronizer.Stats, vars synchronizer.SCVariablesPtr) { +func (n *Node) handleReorg(ctx context.Context, stats *synchronizer.Stats, vars synchronizer.SCVariablesPtr) { if n.mode == ModeCoordinator { - n.coord.SendMsg(coordinator.MsgSyncReorg{ + n.coord.SendMsg(ctx, coordinator.MsgSyncReorg{ Stats: *stats, Vars: vars, }) @@ -491,7 +491,7 @@ func (n *Node) syncLoopFn(ctx context.Context, lastBlock *common.Block) (*common // case: reorg log.Infow("Synchronizer.Sync reorg", "discarded", *discarded) vars := n.sync.SCVars() - n.handleReorg(stats, vars) + n.handleReorg(ctx, stats, vars) return nil, time.Duration(0), nil } else if blockData != nil { // case: new block @@ -500,7 +500,7 @@ func (n *Node) syncLoopFn(ctx context.Context, lastBlock *common.Block) (*common Auction: blockData.Auction.Vars, WDelayer: blockData.WDelayer.Vars, } - n.handleNewBlock(stats, vars, blockData.Rollup.Batches) + n.handleNewBlock(ctx, stats, vars, blockData.Rollup.Batches) return &blockData.Block, time.Duration(0), nil } else { // case: no block @@ -519,7 +519,7 @@ func (n *Node) StartSynchronizer() { // the last synced one) is synchronized stats := n.sync.Stats() vars := n.sync.SCVars() - n.handleNewBlock(stats, vars, []common.BatchData{}) + n.handleNewBlock(n.ctx, stats, vars, []common.BatchData{}) n.wg.Add(1) go func() { diff --git a/synchronizer/synchronizer.go b/synchronizer/synchronizer.go index 077ee35..811d7df 100644 --- a/synchronizer/synchronizer.go +++ b/synchronizer/synchronizer.go @@ -37,6 +37,7 @@ type Stats struct { LastForgeL1TxsNum int64 Auction struct { CurrentSlot common.Slot + NextSlot common.Slot } } } @@ -67,10 +68,11 @@ func NewStatsHolder(firstBlockNum int64, refreshPeriod time.Duration) *StatsHold return &StatsHolder{Stats: stats} } -// UpdateCurrentSlot updates the auction stats -func (s *StatsHolder) UpdateCurrentSlot(slot common.Slot) { +// UpdateCurrentNextSlot updates the auction stats +func (s *StatsHolder) UpdateCurrentNextSlot(current *common.Slot, next *common.Slot) { s.rw.Lock() - s.Sync.Auction.CurrentSlot = slot + s.Sync.Auction.CurrentSlot = *current + s.Sync.Auction.NextSlot = *next s.rw.Unlock() } @@ -129,6 +131,14 @@ func (s *StatsHolder) CopyStats() *Stats { sCopy.Sync.Auction.CurrentSlot.DefaultSlotBid = common.CopyBigInt(s.Sync.Auction.CurrentSlot.DefaultSlotBid) } + if s.Sync.Auction.NextSlot.BidValue != nil { + sCopy.Sync.Auction.NextSlot.BidValue = + common.CopyBigInt(s.Sync.Auction.NextSlot.BidValue) + } + if s.Sync.Auction.NextSlot.DefaultSlotBid != nil { + sCopy.Sync.Auction.NextSlot.DefaultSlotBid = + common.CopyBigInt(s.Sync.Auction.NextSlot.DefaultSlotBid) + } s.rw.RUnlock() return &sCopy } @@ -282,8 +292,39 @@ func (s *Synchronizer) SCVars() SCVariablesPtr { } } +// setSlotCoordinator queries the highest bidder of a slot in the HistoryDB to +// determine the coordinator that can bid in a slot +func (s *Synchronizer) setSlotCoordinator(slot *common.Slot) error { + bidCoord, err := s.historyDB.GetBestBidCoordinator(slot.SlotNum) + if err != nil && tracerr.Unwrap(err) != sql.ErrNoRows { + return tracerr.Wrap(err) + } + if tracerr.Unwrap(err) == sql.ErrNoRows { + slot.BootCoord = true + slot.Forger = s.vars.Auction.BootCoordinator + slot.URL = s.vars.Auction.BootCoordinatorURL + } else if err == nil { + slot.BidValue = bidCoord.BidValue + slot.DefaultSlotBid = bidCoord.DefaultSlotSetBid[slot.SlotNum%6] + // Only if the highest bid value is greater/equal than + // the default slot bid, the bidder is the winner of + // the slot. Otherwise the boot coordinator is the + // winner. + if slot.BidValue.Cmp(slot.DefaultSlotBid) >= 0 { + slot.Bidder = bidCoord.Bidder + slot.Forger = bidCoord.Forger + slot.URL = bidCoord.URL + } else { + slot.BootCoord = true + slot.Forger = s.vars.Auction.BootCoordinator + slot.URL = s.vars.Auction.BootCoordinatorURL + } + } + return nil +} + // firstBatchBlockNum is the blockNum of first batch in that block, if any -func (s *Synchronizer) updateCurrentSlotIfSync(reset bool, firstBatchBlockNum *int64) error { +func (s *Synchronizer) getCurrentSlot(reset bool, firstBatchBlockNum *int64) (*common.Slot, error) { slot := common.Slot{ SlotNum: s.stats.Sync.Auction.CurrentSlot.SlotNum, ForgerCommitment: s.stats.Sync.Auction.CurrentSlot.ForgerCommitment, @@ -294,7 +335,7 @@ func (s *Synchronizer) updateCurrentSlotIfSync(reset bool, firstBatchBlockNum *i 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)) + return nil, tracerr.Wrap(fmt.Errorf("historyDB.GetFirstBatchBySlot: %w", err)) } else if tracerr.Unwrap(err) == sql.ErrNoRows { firstBatchBlockNum = nil } else { @@ -309,30 +350,8 @@ func (s *Synchronizer) updateCurrentSlotIfSync(reset bool, firstBatchBlockNum *i slot.StartBlock, slot.EndBlock = s.consts.Auction.SlotBlocks(slot.SlotNum) // If Synced, update the current coordinator if s.stats.Synced() && blockNum >= s.consts.Auction.GenesisBlockNum { - bidCoord, err := s.historyDB.GetBestBidCoordinator(slot.SlotNum) - if err != nil && tracerr.Unwrap(err) != sql.ErrNoRows { - return tracerr.Wrap(err) - } - if tracerr.Unwrap(err) == sql.ErrNoRows { - slot.BootCoord = true - slot.Forger = s.vars.Auction.BootCoordinator - slot.URL = s.vars.Auction.BootCoordinatorURL - } else if err == nil { - slot.BidValue = bidCoord.BidValue - slot.DefaultSlotBid = bidCoord.DefaultSlotSetBid[slot.SlotNum%6] - // Only if the highest bid value is greater/equal than - // the default slot bid, the bidder is the winner of - // the slot. Otherwise the boot coordinator is the - // winner. - if slot.BidValue.Cmp(slot.DefaultSlotBid) >= 0 { - slot.Bidder = bidCoord.Bidder - slot.Forger = bidCoord.Forger - slot.URL = bidCoord.URL - } else { - slot.BootCoord = true - slot.Forger = s.vars.Auction.BootCoordinator - slot.URL = s.vars.Auction.BootCoordinatorURL - } + if err := s.setSlotCoordinator(&slot); err != nil { + return nil, tracerr.Wrap(err) } if firstBatchBlockNum != nil && s.consts.Auction.RelativeBlock(*firstBatchBlockNum) < @@ -344,15 +363,57 @@ func (s *Synchronizer) updateCurrentSlotIfSync(reset bool, firstBatchBlockNum *i // BEGIN SANITY CHECK canForge, err := s.ethClient.AuctionCanForge(slot.Forger, blockNum) if err != nil { - return tracerr.Wrap(err) + return nil, tracerr.Wrap(err) } if !canForge { - return tracerr.Wrap(fmt.Errorf("Synchronized value of forger address for closed slot "+ + return nil, tracerr.Wrap(fmt.Errorf("Synchronized value of forger address for closed slot "+ "differs from smart contract: %+v", slot)) } // END SANITY CHECK } - s.stats.UpdateCurrentSlot(slot) + return &slot, nil +} + +func (s *Synchronizer) getNextSlot() (*common.Slot, error) { + // 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) + 1 + slot := common.Slot{ + SlotNum: slotNum, + ForgerCommitment: false, + } + slot.StartBlock, slot.EndBlock = s.consts.Auction.SlotBlocks(slot.SlotNum) + // If Synced, update the current coordinator + if s.stats.Synced() && blockNum >= s.consts.Auction.GenesisBlockNum { + if err := s.setSlotCoordinator(&slot); err != nil { + return nil, tracerr.Wrap(err) + } + + // TODO: Remove this SANITY CHECK once this code is tested enough + // BEGIN SANITY CHECK + canForge, err := s.ethClient.AuctionCanForge(slot.Forger, slot.StartBlock) + if err != nil { + return nil, tracerr.Wrap(err) + } + if !canForge { + return nil, tracerr.Wrap(fmt.Errorf("Synchronized value of forger address for closed slot "+ + "differs from smart contract: %+v", slot)) + } + // END SANITY CHECK + } + return &slot, nil +} + +func (s *Synchronizer) updateCurrentNextSlotIfSync(reset bool, firstBatchBlockNum *int64) error { + current, err := s.getCurrentSlot(reset, firstBatchBlockNum) + if err != nil { + return tracerr.Wrap(err) + } + next, err := s.getNextSlot() + if err != nil { + return tracerr.Wrap(err) + } + s.stats.UpdateCurrentNextSlot(current, next) return nil } @@ -530,7 +591,7 @@ func (s *Synchronizer) Sync2(ctx context.Context, lastSavedBlock *common.Block) if len(rollupData.Batches) > 0 { firstBatchBlockNum = &rollupData.Batches[0].Batch.EthBlockNum } - if err := s.updateCurrentSlotIfSync(false, firstBatchBlockNum); err != nil { + if err := s.updateCurrentNextSlotIfSync(false, firstBatchBlockNum); err != nil { return nil, nil, tracerr.Wrap(err) } @@ -680,7 +741,7 @@ func (s *Synchronizer) resetState(block *common.Block) error { s.stats.UpdateSync(block, &batchNum, &lastL1BatchBlockNum, lastForgeL1TxsNum) - if err := s.updateCurrentSlotIfSync(true, nil); err != nil { + if err := s.updateCurrentNextSlotIfSync(true, nil); err != nil { return tracerr.Wrap(err) } return nil diff --git a/test/ethclient.go b/test/ethclient.go index bc8ee83..7a5fe05 100644 --- a/test/ethclient.go +++ b/test/ethclient.go @@ -11,6 +11,8 @@ import ( "time" "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + ethKeystore "github.com/ethereum/go-ethereum/accounts/keystore" ethCommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/hermeznetwork/hermez-node/common" @@ -179,7 +181,6 @@ func (a *AuctionBlock) canForge(forger ethCommon.Address, blockNum int64) (bool, } slotToForge := a.getSlotNumber(blockNum) - // fmt.Printf("DBG canForge slot: %v\n", slotToForge) // Get the relativeBlock to check if the slotDeadline has been exceeded relativeBlock := blockNum - (a.Constants.GenesisBlockNum + (slotToForge * int64(a.Constants.BlocksPerSlot))) @@ -616,6 +617,38 @@ func (c *Client) EthChainID() (*big.Int, error) { return c.chainID, nil } +// EthPendingNonceAt returns the account nonce of the given account in the pending +// state. This is the nonce that should be used for the next transaction. +func (c *Client) EthPendingNonceAt(ctx context.Context, account ethCommon.Address) (uint64, error) { + // NOTE: For now Client doesn't simulate nonces + return 0, nil +} + +// EthNonceAt returns the account nonce of the given account. The block number can +// be nil, in which case the nonce is taken from the latest known block. +func (c *Client) EthNonceAt(ctx context.Context, account ethCommon.Address, blockNumber *big.Int) (uint64, error) { + // NOTE: For now Client doesn't simulate nonces + return 0, nil +} + +// EthSuggestGasPrice retrieves the currently suggested gas price to allow a +// timely execution of a transaction. +func (c *Client) EthSuggestGasPrice(ctx context.Context) (*big.Int, error) { + // NOTE: For now Client doesn't simulate gasPrice + return big.NewInt(0), nil +} + +// EthKeyStore returns the keystore in the Client +func (c *Client) EthKeyStore() *ethKeystore.KeyStore { + return nil +} + +// EthCall runs the transaction as a call (without paying) in the local node at +// blockNum. +func (c *Client) EthCall(ctx context.Context, tx *types.Transaction, blockNum *big.Int) ([]byte, error) { + return nil, tracerr.Wrap(common.ErrTODO) +} + // EthLastBlock returns the last blockNum func (c *Client) EthLastBlock() (int64, error) { c.rw.RLock() @@ -912,7 +945,7 @@ func (c *Client) newTransaction(name string, value interface{}) *types.Transacti } // RollupForgeBatch is the interface to call the smart contract function -func (c *Client) RollupForgeBatch(args *eth.RollupForgeBatchArgs) (tx *types.Transaction, err error) { +func (c *Client) RollupForgeBatch(args *eth.RollupForgeBatchArgs, auth *bind.TransactOpts) (tx *types.Transaction, err error) { c.rw.Lock() defer c.rw.Unlock() cpy := c.nextBlock().copy() @@ -1822,7 +1855,7 @@ func (c *Client) CtlAddBlocks(blocks []common.BlockData) (err error) { ProofA: [2]*big.Int{}, // Intentionally empty ProofB: [2][2]*big.Int{}, // Intentionally empty ProofC: [2]*big.Int{}, // Intentionally empty - }); err != nil { + }, nil); err != nil { return tracerr.Wrap(err) } } diff --git a/test/ethclient_test.go b/test/ethclient_test.go index b05bee7..e3600aa 100644 --- a/test/ethclient_test.go +++ b/test/ethclient_test.go @@ -98,7 +98,7 @@ func TestClientAuction(t *testing.T) { _, err := c.AuctionBidSimple(0, big.NewInt(1)) assert.Equal(t, errBidClosed, tracerr.Unwrap(err)) - _, err = c.AuctionBidSimple(4322, big.NewInt(1)) + _, err = c.AuctionBidSimple(4323, big.NewInt(1)) assert.Equal(t, errBidNotOpen, tracerr.Unwrap(err)) // 101 % 6 = 5; defaultSlotSetBid[5] = 1500; 1500 + 10% = 1650