diff --git a/coordinator/batch.go b/coordinator/batch.go index 1bbf30c..486baeb 100644 --- a/coordinator/batch.go +++ b/coordinator/batch.go @@ -1,6 +1,7 @@ package coordinator import ( + "github.com/ethereum/go-ethereum/core/types" "github.com/hermeznetwork/hermez-node/common" ) @@ -18,6 +19,7 @@ type BatchInfo struct { L1OperatorTxs []*common.L1Tx L2Txs []*common.PoolL2Tx // FeesInfo + ethTx *types.Transaction } // NewBatchInfo creates a new BatchInfo with the given batchNum & @@ -52,3 +54,8 @@ func (bi *BatchInfo) SetServerProof(serverProof ServerProofInterface) { func (bi *BatchInfo) SetProof(proof *Proof) { bi.proof = proof } + +// SetEthTx sets the ethTx to the BatchInfo data structure +func (bi *BatchInfo) SetEthTx(ethTx *types.Transaction) { + bi.ethTx = ethTx +} diff --git a/coordinator/coordinator.go b/coordinator/coordinator.go index 2edfe46..ee1abf2 100644 --- a/coordinator/coordinator.go +++ b/coordinator/coordinator.go @@ -1,18 +1,18 @@ package coordinator import ( + "context" "fmt" - "sync" + "time" ethCommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/hermeznetwork/hermez-node/batchbuilder" "github.com/hermeznetwork/hermez-node/common" "github.com/hermeznetwork/hermez-node/db/historydb" "github.com/hermeznetwork/hermez-node/eth" "github.com/hermeznetwork/hermez-node/log" "github.com/hermeznetwork/hermez-node/txselector" - kvdb "github.com/iden3/go-merkletree/db" - "github.com/iden3/go-merkletree/db/memory" ) var errTODO = fmt.Errorf("TODO") @@ -28,9 +28,9 @@ type Config struct { // Coordinator implements the Coordinator type type Coordinator struct { - forging bool - rw *sync.RWMutex - isForgeSeq bool // WIP just for testing while implementing + forging bool + // rw *sync.RWMutex + // isForgeSeq bool // WIP just for testing while implementing config Config @@ -42,8 +42,9 @@ type Coordinator struct { txsel *txselector.TxSelector batchBuilder *batchbuilder.BatchBuilder - ethClient eth.ClientInterface - ethTxStore kvdb.Storage + ethClient eth.ClientInterface + ethTxs []*types.Transaction + // ethTxStore kvdb.Storage } // NewCoordinator creates a new Coordinator @@ -64,17 +65,30 @@ func NewCoordinator(conf Config, txsel: txsel, batchBuilder: bb, ethClient: ethClient, - ethTxStore: memory.NewMemoryStorage(), - rw: &sync.RWMutex{}, + + ethTxs: make([]*types.Transaction, 0), + // ethTxStore: memory.NewMemoryStorage(), + // rw: &sync.RWMutex{}, } return &c } +// TODO(Edu): Change the current design of the coordinator structur: +// - Move Start and Stop functions (from node/node.go) here +// - Add concept of StartPipeline, StopPipeline, that spawns and stops the goroutines +// - Add a Manager that calls StartPipeline and StopPipeline, checks when it's time to forge, schedules new batches, etc. +// - Add a TxMonitor that monitors successful ForgeBatch ethereum transactions and waits for N blocks of confirmation, and reports back errors to the Manager. + // ForgeLoopFn is the function ran in a loop that checks if it's time to forge // and forges a batch if so and sends it to outBatchCh. Returns true if it's // the coordinator turn to forge. func (c *Coordinator) ForgeLoopFn(outBatchCh chan *BatchInfo, stopCh chan bool) (forgetime bool, err error) { - if !c.isForgeSequence() { + // TODO: Move the logic to check if it's forge time or not outside the pipeline + isForgeSequence, err := c.isForgeSequence() + if err != nil { + return false, err + } + if !isForgeSequence { if c.forging { log.Info("ForgeLoopFn: forging state end") c.forging = false @@ -106,6 +120,12 @@ func (c *Coordinator) ForgeLoopFn(outBatchCh chan *BatchInfo, stopCh chan bool) // if c.synchronizer.Reorg(): _ = c.handleReorg() + defer func() { + if err == ErrStop { + log.Info("ForgeLoopFn: forgeLoopFn stopped") + } + }() + // 0. Wait for an available server proof // blocking call serverProof, err := c.serverProofPool.Get(stopCh) @@ -134,10 +154,14 @@ func (c *Coordinator) ForgeLoopFn(outBatchCh chan *BatchInfo, stopCh chan bool) // GetProofCallForgeLoopFn is the function ran in a loop that gets a forged // batch via inBatchCh, waits for the proof server to finish, calls the ForgeBatch // function in the Rollup Smart Contract, and sends the batch to outBatchCh. -func (c *Coordinator) GetProofCallForgeLoopFn(inBatchCh, outBatchCh chan *BatchInfo, stopCh chan bool) error { +func (c *Coordinator) GetProofCallForgeLoopFn(inBatchCh, outBatchCh chan *BatchInfo, stopCh chan bool) (err error) { + defer func() { + if err == ErrStop { + log.Info("GetProofCallForgeLoopFn: forgeLoopFn stopped") + } + }() select { case <-stopCh: - log.Info("GetProofCallForgeLoopFn: forgeLoopFn stopped") return ErrStop case batchInfo := <-inBatchCh: log.Debugw("GetProofCallForgeLoopFn: getProofCallForge start", "batchNum", batchInfo.batchNum) @@ -153,14 +177,18 @@ func (c *Coordinator) GetProofCallForgeLoopFn(inBatchCh, outBatchCh chan *BatchI // ForgeCallConfirmLoopFn is the function ran in a loop that gets a batch that // has been sent to the Rollup Smart Contract via inBatchCh and waits for the // ethereum transaction confirmation. -func (c *Coordinator) ForgeCallConfirmLoopFn(inBatchCh chan *BatchInfo, stopCh chan bool) error { +func (c *Coordinator) ForgeCallConfirmLoopFn(inBatchCh chan *BatchInfo, stopCh chan bool) (err error) { + defer func() { + if err == ErrStop { + log.Info("ForgeCallConfirmLoopFn: forgeConfirmLoopFn stopped") + } + }() select { case <-stopCh: - log.Info("ForgeCallConfirmLoopFn: forgeConfirmLoopFn stopped") return ErrStop case batchInfo := <-inBatchCh: log.Debugw("ForgeCallConfirmLoopFn: forgeCallConfirm start", "batchNum", batchInfo.batchNum) - if err := c.forgeCallConfirm(batchInfo); err != nil { + if err := c.forgeCallConfirm(batchInfo, stopCh); err != nil { return err } log.Debugw("ForgeCallConfirmLoopFn: forgeCallConfirm end", "batchNum", batchInfo.batchNum) @@ -244,13 +272,15 @@ func (c *Coordinator) getProofCallForge(batchInfo *BatchInfo, stopCh chan bool) } batchInfo.SetProof(proof) forgeBatchArgs := c.prepareForgeBatchArgs(batchInfo) - _, err = c.ethClient.RollupForgeBatch(forgeBatchArgs) + ethTx, err := c.ethClient.RollupForgeBatch(forgeBatchArgs) if err != nil { return err } + // TODO: Move this to the next step (forgeCallConfirm) log.Debugf("ethClient ForgeCall sent, batchNum: %d", c.batchNum) + batchInfo.SetEthTx(ethTx) - // TODO once tx data type is defined, store ethTx (returned by ForgeCall) + // TODO(FUTURE) once tx data type is defined, store ethTx (returned by ForgeCall) // TBD if use ethTxStore as a disk k-v database, or use a Queue // tx, err := c.ethTxStore.NewTx() // if err != nil { @@ -264,13 +294,46 @@ func (c *Coordinator) getProofCallForge(batchInfo *BatchInfo, stopCh chan bool) return nil } -func (c *Coordinator) forgeCallConfirm(batchInfo *BatchInfo) error { +func (c *Coordinator) forgeCallConfirm(batchInfo *BatchInfo, stopCh chan bool) error { // TODO strategy of this sequence TBD // confirm eth txs and mark them as accepted sequence + // IDEA: Keep an array in Coordinator with the list of sent ethTx. + // Here, loop over them and only delete them once the number of + // confirmed blocks is over a configured value. If the tx is rejected, + // return error. // ethTx := ethTxStore.GetFirstPending() // waitForAccepted(ethTx) // blocking call, returns once the ethTx is mined // ethTxStore.MarkAccepted(ethTx) - return nil + txID := batchInfo.ethTx.Hash() + // TODO: Follow EthereumClient.waitReceipt logic + count := 0 + // TODO: Define this waitTime in the config + waitTime := 100 * time.Millisecond //nolint:gomnd + select { + case <-time.After(waitTime): + receipt, err := c.ethClient.EthTransactionReceipt(context.TODO(), txID) + if err != nil { + return err + } + if receipt != nil { + if receipt.Status == types.ReceiptStatusFailed { + return fmt.Errorf("receipt status is failed") + } else if receipt.Status == types.ReceiptStatusSuccessful { + return nil + } + } + // TODO: Call go-ethereum: + // if err == nil && receipt == nil : + // `func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) {` + count++ + if time.Duration(count)*waitTime > 60*time.Second { + log.Warnw("Waiting for ethTx receipt for more than 60 seconds", "tx", batchInfo.ethTx) + // TODO: Decide if we resend the Tx with higher gas price + } + case <-stopCh: + return ErrStop + } + return fmt.Errorf("timeout") } func (c *Coordinator) handleReorg() error { @@ -278,10 +341,17 @@ func (c *Coordinator) handleReorg() error { } // isForgeSequence returns true if the node is the Forger in the current ethereum block -func (c *Coordinator) isForgeSequence() bool { - c.rw.RLock() - defer c.rw.RUnlock() - return c.isForgeSeq // TODO +func (c *Coordinator) isForgeSequence() (bool, error) { + // TODO: Consider checking if we can forge by quering the Synchronizer instead of using ethClient + blockNum, err := c.ethClient.EthCurrentBlock() + if err != nil { + return false, err + } + addr, err := c.ethClient.EthAddress() + if err != nil { + return false, err + } + return c.ethClient.AuctionCanForge(*addr, blockNum+1) } func (c *Coordinator) purgeRemoveByTimeout() error { diff --git a/coordinator/coordinator_test.go b/coordinator/coordinator_test.go index 3adb136..27bc7ee 100644 --- a/coordinator/coordinator_test.go +++ b/coordinator/coordinator_test.go @@ -2,10 +2,12 @@ package coordinator import ( "io/ioutil" + "math/big" "os" "testing" "time" + ethCommon "github.com/ethereum/go-ethereum/common" "github.com/hermeznetwork/hermez-node/batchbuilder" dbUtils "github.com/hermeznetwork/hermez-node/db" "github.com/hermeznetwork/hermez-node/db/historydb" @@ -65,8 +67,9 @@ func (cn *CoordNode) Start() { cn.stopForge = make(chan bool) cn.stopGetProofCallForge = make(chan bool) cn.stopForgeCallConfirm = make(chan bool) - batchCh0 := make(chan *BatchInfo) - batchCh1 := make(chan *BatchInfo) + queueSize := 8 + batchCh0 := make(chan *BatchInfo, queueSize) + batchCh1 := make(chan *BatchInfo, queueSize) go func() { for { @@ -78,6 +81,7 @@ func (cn *CoordNode) Start() { return } else if err != nil { log.Errorw("CoordNode ForgeLoopFn", "error", err) + time.Sleep(200 * time.Millisecond) // Avoid overflowing log with errors } else if !forge { time.Sleep(200 * time.Millisecond) } @@ -133,17 +137,38 @@ func (t *timer) Time() int64 { return currentTime } +func waitForSlot(t *testing.T, c *test.Client, slot int64) { + for { + blockNum, err := c.EthCurrentBlock() + require.Nil(t, err) + nextBlockSlot, err := c.AuctionGetSlotNumber(blockNum + 1) + require.Nil(t, err) + if nextBlockSlot == slot { + break + } + c.CtlMineBlock() + } +} + func TestCoordinator(t *testing.T) { txsel, bb := newTestModules(t) conf := Config{} hdb := &historydb.HistoryDB{} - serverProofs := []ServerProofInterface{&ServerProof{}, &ServerProof{}} + serverProofs := []ServerProofInterface{&ServerProofMock{}, &ServerProofMock{}} var timer timer ethClientSetup := test.NewClientSetupExample() - addr := ethClientSetup.AuctionVariables.BootCoordinator - ethClient := test.NewClient(true, &timer, addr, ethClientSetup) + addr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6") + ethClient := test.NewClient(true, &timer, &addr, ethClientSetup) + + // Bid for slot 2 and 4 + _, err := ethClient.AuctionRegisterCoordinator(addr, "https://foo.bar") + require.Nil(t, err) + _, err = ethClient.AuctionBid(2, big.NewInt(9999), addr) + require.Nil(t, err) + _, err = ethClient.AuctionBid(4, big.NewInt(9999), addr) + require.Nil(t, err) c := NewCoordinator(conf, hdb, txsel, bb, serverProofs, ethClient) cn := NewCoordNode(c) @@ -151,24 +176,18 @@ func TestCoordinator(t *testing.T) { time.Sleep(1 * time.Second) // simulate forgeSequence time + waitForSlot(t, ethClient, 2) log.Info("simulate entering in forge time") - c.rw.Lock() - c.isForgeSeq = true - c.rw.Unlock() time.Sleep(1 * time.Second) // simulate going out from forgeSequence + waitForSlot(t, ethClient, 3) log.Info("simulate going out from forge time") - c.rw.Lock() - c.isForgeSeq = false - c.rw.Unlock() time.Sleep(1 * time.Second) // simulate entering forgeSequence time again + waitForSlot(t, ethClient, 4) log.Info("simulate entering in forge time again") - c.rw.Lock() - c.isForgeSeq = true - c.rw.Unlock() time.Sleep(2 * time.Second) // simulate stopping forgerLoop by channel diff --git a/coordinator/proofpool.go b/coordinator/proofpool.go index 41f7745..c56deae 100644 --- a/coordinator/proofpool.go +++ b/coordinator/proofpool.go @@ -28,11 +28,13 @@ func NewServerProof(URL string) *ServerProof { // CalculateProof sends the *common.ZKInputs to the ServerProof to compute the // Proof func (p *ServerProof) CalculateProof(zkInputs *common.ZKInputs) error { + log.Error("TODO") return errTODO } // GetProof retreives the Proof from the ServerProof func (p *ServerProof) GetProof(stopCh chan bool) (*Proof, error) { + log.Error("TODO") return nil, errTODO } diff --git a/eth/auction.go b/eth/auction.go index d2cccb8..46daa3b 100644 --- a/eth/auction.go +++ b/eth/auction.go @@ -240,11 +240,11 @@ type AuctionInterface interface { AuctionUpdateCoordinatorInfo(forgerAddress ethCommon.Address, newWithdrawAddress ethCommon.Address, newURL string) (*types.Transaction, error) // Slot Info + AuctionGetSlotNumber(blockNum int64) (int64, error) AuctionGetCurrentSlotNumber() (int64, error) AuctionGetMinBidBySlot(slot int64) (*big.Int, error) AuctionGetDefaultSlotSetBid(slotSet uint8) (*big.Int, error) AuctionGetSlotSet(slot int64) (*big.Int, error) - AuctionGetSlotNumber(blockNum int64) (*big.Int, error) // Bidding // AuctionTokensReceived(operator, from, to ethCommon.Address, amount *big.Int, @@ -698,7 +698,7 @@ func (c *AuctionClient) AuctionGetDefaultSlotSetBid(slotSet uint8) (*big.Int, er } // AuctionGetSlotNumber is the interface to call the smart contract function -func (c *AuctionClient) AuctionGetSlotNumber(blockNum int64) (*big.Int, error) { +func (c *AuctionClient) AuctionGetSlotNumber(blockNum int64) (int64, error) { var slot *big.Int if err := c.client.Call(func(ec *ethclient.Client) error { auction, err := HermezAuctionProtocol.NewHermezAuctionProtocol(c.address, ec) @@ -709,9 +709,9 @@ func (c *AuctionClient) AuctionGetSlotNumber(blockNum int64) (*big.Int, error) { slot, err = auction.GetSlotNumber(nil, blockNumBig) return err }); err != nil { - return big.NewInt(0), err + return 0, err } - return slot, nil + return slot.Int64(), nil } // AuctionBid is the interface to call the smart contract function diff --git a/eth/ethereum.go b/eth/ethereum.go index 89617f8..e74393d 100644 --- a/eth/ethereum.go +++ b/eth/ethereum.go @@ -21,6 +21,8 @@ type EthereumInterface interface { EthCurrentBlock() (int64, error) // EthHeaderByNumber(context.Context, *big.Int) (*types.Header, error) EthBlockByNumber(context.Context, int64) (*common.Block, error) + EthAddress() (*ethCommon.Address, error) + EthTransactionReceipt(context.Context, ethCommon.Hash) (*types.Receipt, error) } var ( @@ -90,6 +92,14 @@ func (c *EthereumClient) Account() *accounts.Account { return c.account } +// EthAddress returns the ethereum address of the account loaded into the EthereumClient +func (c *EthereumClient) EthAddress() (*ethCommon.Address, error) { + if c.account == nil { + return nil, ErrAccountNil + } + return &c.account.Address, 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. @@ -186,16 +196,21 @@ func (c *EthereumClient) GetReceipt(tx *types.Transaction) (*types.Receipt, erro return c.waitReceipt(ctx, tx, 0) } +// EthTransactionReceipt returns the transaction receipt of the given txHash +func (c *EthereumClient) EthTransactionReceipt(ctx context.Context, txHash ethCommon.Hash) (*types.Receipt, error) { + return c.client.TransactionReceipt(ctx, txHash) +} + func (c *EthereumClient) waitReceipt(ctx context.Context, tx *types.Transaction, timeout time.Duration) (*types.Receipt, error) { var err error var receipt *types.Receipt - txid := tx.Hash() - log.Debugw("Waiting for receipt", "tx", txid.Hex()) + txHash := tx.Hash() + log.Debugw("Waiting for receipt", "tx", txHash.Hex()) start := time.Now() for { - receipt, err = c.client.TransactionReceipt(ctx, txid) + receipt, err = c.client.TransactionReceipt(ctx, txHash) if receipt != nil || time.Since(start) >= timeout { break } @@ -203,15 +218,15 @@ func (c *EthereumClient) waitReceipt(ctx context.Context, tx *types.Transaction, } if receipt != nil && receipt.Status == types.ReceiptStatusFailed { - log.Errorw("Failed transaction", "tx", txid.Hex()) + log.Errorw("Failed transaction", "tx", txHash.Hex()) return receipt, ErrReceiptStatusFailed } if receipt == nil { - log.Debugw("Pendingtransaction / Wait receipt timeout", "tx", txid.Hex(), "lasterr", err) + log.Debugw("Pendingtransaction / Wait receipt timeout", "tx", txHash.Hex(), "lasterr", err) return receipt, ErrReceiptNotReceived } - log.Debugw("Successful transaction", "tx", txid.Hex()) + log.Debugw("Successful transaction", "tx", txHash.Hex()) return receipt, err } diff --git a/go.mod b/go.mod index 77e6248..06d0650 100644 --- a/go.mod +++ b/go.mod @@ -24,5 +24,6 @@ require ( go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.16.0 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 + golang.org/x/tools/gopls v0.5.0 // indirect gopkg.in/go-playground/validator.v9 v9.29.1 ) diff --git a/go.sum b/go.sum index a7dcd7b..0e91769 100644 --- a/go.sum +++ b/go.sum @@ -234,6 +234,8 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -494,6 +496,7 @@ 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/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.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= @@ -510,6 +513,8 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shirou/gopsutil v2.20.5+incompatible h1:tYH07UPoQt0OCQdgWWMgYHy3/a9bcxNpBIysykNIP7I= github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= @@ -581,6 +586,8 @@ github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+m github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +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= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -648,6 +655,8 @@ 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-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= @@ -672,6 +681,8 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -681,6 +692,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ 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/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -732,15 +745,24 @@ 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-20200731060945-b5fad4ed8dd6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +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/tools v0.0.0-20200929223013-bf155c11ec6f h1:7+Nz9MyPqt2qMCTvNiRy1G0zYfkB7UCa+ayT6uVvbyI= +golang.org/x/tools/gopls v0.5.0 h1:XEmO9RylgmaXp33iGrWfCGopVYDGBmLy+KmsIsfIo8Y= +golang.org/x/tools/gopls v0.5.0/go.mod h1:bm7s/5W/faSLxWyOWFtTI+5lZQQVdtksvEXdIfkFE74= 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= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -764,6 +786,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks 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/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/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= @@ -796,6 +819,7 @@ gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRN gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 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= @@ -808,5 +832,11 @@ 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= +mvdan.cc/gofumpt v0.0.0-20200802201014-ab5a8192947d h1:t8TAw9WgTLghti7RYkpPmqk4JtQ3+wcP5GgZqgWeWLQ= +mvdan.cc/gofumpt v0.0.0-20200802201014-ab5a8192947d/go.mod h1:bzrjFmaD6+xqohD3KYP0H2FEuxknnBmyyOxdhLdaIws= +mvdan.cc/xurls/v2 v2.2.0 h1:NSZPykBXJFCetGZykLAxaL6SIpvbVy/UFEniIfHAa8A= +mvdan.cc/xurls/v2 v2.2.0/go.mod h1:EV1RMtya9D6G5DMYPGD8zTQzaHet6Jh8gFlRgGRJeO8= 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 273b0e5..0e8c464 100644 --- a/node/node.go +++ b/node/node.go @@ -144,8 +144,9 @@ func (n *Node) StartCoordinator() { n.stoppedGetProofCallForge = make(chan bool) n.stoppedForgeCallConfirm = make(chan bool) - batchCh0 := make(chan *coordinator.BatchInfo) - batchCh1 := make(chan *coordinator.BatchInfo) + queueSize := 1 + batchCh0 := make(chan *coordinator.BatchInfo, queueSize) + batchCh1 := make(chan *coordinator.BatchInfo, queueSize) go func() { defer func() { n.stoppedForge <- true }() diff --git a/test/ethclient.go b/test/ethclient.go index a81d232..128fc19 100644 --- a/test/ethclient.go +++ b/test/ethclient.go @@ -33,10 +33,17 @@ type RollupBlock struct { State eth.RollupState Vars eth.RollupVariables Events eth.RollupEvents + Txs map[ethCommon.Hash]*types.Transaction Constants *eth.RollupConstants Eth *EthereumBlock } +func (r *RollupBlock) addTransaction(tx *types.Transaction) *types.Transaction { + txHash := tx.Hash() + r.Txs[txHash] = tx + return tx +} + var ( errBidClosed = fmt.Errorf("Bid has already been closed") errBidNotOpen = fmt.Errorf("Bid has not been opened yet") @@ -49,10 +56,17 @@ type AuctionBlock struct { State eth.AuctionState Vars eth.AuctionVariables Events eth.AuctionEvents + Txs map[ethCommon.Hash]*types.Transaction Constants *eth.AuctionConstants Eth *EthereumBlock } +func (a *AuctionBlock) addTransaction(tx *types.Transaction) *types.Transaction { + txHash := tx.Hash() + a.Txs[txHash] = tx + return tx +} + func (a *AuctionBlock) getSlotNumber(blockNumber int64) int64 { if a.Eth.BlockNum >= a.Constants.GenesisBlockNum { return (blockNumber - a.Constants.GenesisBlockNum) / int64(a.Constants.BlocksPerSlot) @@ -286,7 +300,7 @@ type Timer interface { type Client struct { rw *sync.RWMutex log bool - addr ethCommon.Address + addr *ethCommon.Address rollupConstants *eth.RollupConstants auctionConstants *eth.AuctionConstants blocks map[int64]*Block @@ -302,7 +316,7 @@ type Client struct { // NewClient returns a new test Client that implements the eth.IClient // interface, at the given initialBlockNumber. -func NewClient(l bool, timer Timer, addr ethCommon.Address, setup *ClientSetup) *Client { +func NewClient(l bool, timer Timer, addr *ethCommon.Address, setup *ClientSetup) *Client { blocks := make(map[int64]*Block) blockNum := int64(0) @@ -326,6 +340,7 @@ func NewClient(l bool, timer Timer, addr ethCommon.Address, setup *ClientSetup) CurrentIdx: 0, }, Vars: *setup.RollupVariables, + Txs: make(map[ethCommon.Hash]*types.Transaction), Events: eth.NewRollupEvents(), Constants: setup.RollupConstants, }, @@ -336,6 +351,7 @@ func NewClient(l bool, timer Timer, addr ethCommon.Address, setup *ClientSetup) Coordinators: make(map[ethCommon.Address]*eth.Coordinator), }, Vars: *setup.AuctionVariables, + Txs: make(map[ethCommon.Hash]*types.Transaction), Events: eth.NewAuctionEvents(), Constants: setup.AuctionConstants, }, @@ -468,6 +484,30 @@ func (c *Client) EthCurrentBlock() (int64, error) { return c.blockNum, nil } +// EthTransactionReceipt returns the transaction receipt of the given txHash +func (c *Client) EthTransactionReceipt(ctx context.Context, txHash ethCommon.Hash) (*types.Receipt, error) { + c.rw.RLock() + defer c.rw.RUnlock() + + for i := int64(0); i < c.blockNum; i++ { + b := c.blocks[i] + _, ok := b.Rollup.Txs[txHash] + if !ok { + _, ok = b.Auction.Txs[txHash] + } + if ok { + return &types.Receipt{ + TxHash: txHash, + Status: types.ReceiptStatusSuccessful, + BlockHash: b.Eth.Hash, + BlockNumber: big.NewInt(b.Eth.BlockNum), + }, nil + } + } + + return nil, nil +} + // func newHeader(number *big.Int) *types.Header { // return &types.Header{ // Number: number, @@ -499,6 +539,14 @@ func (c *Client) EthBlockByNumber(ctx context.Context, blockNum int64) (*common. }, nil } +// EthAddress returns the ethereum address of the account loaded into the Client +func (c *Client) EthAddress() (*ethCommon.Address, error) { + if c.addr == nil { + return nil, eth.ErrAccountNil + } + return c.addr, nil +} + var errTODO = fmt.Errorf("TODO: Not implemented yet") // @@ -533,7 +581,7 @@ type transactionData struct { Value interface{} } -func (c *Client) newTransaction(name string, value interface{}) *types.Transaction { +func newTransaction(name string, value interface{}) *types.Transaction { data, err := json.Marshal(transactionData{name, value}) if err != nil { panic(err) @@ -548,9 +596,12 @@ func (c *Client) RollupForgeBatch(args *eth.RollupForgeBatchArgs) (tx *types.Tra defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } a := c.nextBlock().Auction - ok, err := a.canForge(c.addr, a.Eth.BlockNum) + ok, err := a.canForge(*c.addr, a.Eth.BlockNum) if err != nil { return nil, err } @@ -561,11 +612,15 @@ func (c *Client) RollupForgeBatch(args *eth.RollupForgeBatchArgs) (tx *types.Tra // TODO: Verify proof // Auction - err = a.forge(c.addr) + err = a.forge(*c.addr) if err != nil { return nil, err } + // TODO: If successful, store the tx in a successful array. + // TODO: If failed, store the tx in a failed array. + // TODO: Add method to move the tx to another block, reapply it there, and possibly go from successful to failed. + return c.addBatch(args) } @@ -595,7 +650,7 @@ func (c *Client) addBatch(args *eth.RollupForgeBatchArgs) (*types.Transaction, e r.State.MapL1TxQueue[r.State.LastToForgeL1TxsNum] = eth.NewQueueStruct() } } - ethTx := c.newTransaction("forgebatch", args) + ethTx := r.addTransaction(newTransaction("forgebatch", args)) c.forgeBatchArgsPending[ethTx.Hash()] = args r.Events.ForgeBatch = append(r.Events.ForgeBatch, eth.RollupEventForgeBatch{ BatchNum: int64(len(r.State.ExitRoots)), @@ -611,6 +666,9 @@ func (c *Client) RollupAddToken(tokenAddress ethCommon.Address) (tx *types.Trans defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } nextBlock := c.nextBlock() r := nextBlock.Rollup @@ -622,7 +680,7 @@ func (c *Client) RollupAddToken(tokenAddress ethCommon.Address) (tx *types.Trans r.State.TokenList = append(r.State.TokenList, tokenAddress) r.Events.AddToken = append(r.Events.AddToken, eth.RollupEventAddToken{Address: tokenAddress, TokenID: uint32(len(r.State.TokenList) - 1)}) - return c.newTransaction("addtoken", tokenAddress), nil + return r.addTransaction(newTransaction("addtoken", tokenAddress)), nil } // RollupWithdrawSNARK is the interface to call the smart contract function @@ -636,6 +694,9 @@ func (c *Client) RollupWithdraw(tokenID int64, balance *big.Int, babyPubKey *bab defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } log.Error("TODO") return nil, errTODO @@ -647,6 +708,9 @@ func (c *Client) RollupForceExit(fromIdx int64, amountF common.Float16, tokenID defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } log.Error("TODO") return nil, errTODO @@ -658,6 +722,9 @@ func (c *Client) RollupForceTransfer(fromIdx int64, amountF common.Float16, toke defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } log.Error("TODO") return nil, errTODO @@ -669,6 +736,9 @@ func (c *Client) RollupCreateAccountDepositTransfer(babyPubKey babyjub.PublicKey defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } log.Error("TODO") return nil, errTODO @@ -689,6 +759,9 @@ func (c *Client) RollupDepositTransfer(fromIdx int64, loadAmountF, amountF commo defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } log.Error("TODO") return nil, errTODO @@ -700,6 +773,9 @@ func (c *Client) RollupDeposit(fromIdx int64, loadAmountF common.Float16, tokenI defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } log.Error("TODO") return nil, errTODO @@ -711,6 +787,9 @@ func (c *Client) RollupCreateAccountDepositFromRelayer(accountCreationAuthSig [] defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } log.Error("TODO") return nil, errTODO @@ -722,6 +801,9 @@ func (c *Client) RollupCreateAccountDeposit(babyPubKey babyjub.PublicKey, loadAm defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } log.Error("TODO") return nil, errTODO @@ -760,6 +842,9 @@ func (c *Client) RollupUpdateForgeL1L2BatchTimeout(newForgeL1Timeout int64) (tx defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } log.Error("TODO") return nil, errTODO @@ -771,6 +856,9 @@ func (c *Client) RollupUpdateFeeAddToken(newFeeAddToken *big.Int) (tx *types.Tra defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } log.Error("TODO") return nil, errTODO @@ -835,6 +923,9 @@ func (c *Client) AuctionSetSlotDeadline(newDeadline uint8) (tx *types.Transactio defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } log.Error("TODO") return nil, errTODO @@ -855,6 +946,9 @@ func (c *Client) AuctionSetOpenAuctionSlots(newOpenAuctionSlots uint16) (tx *typ defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } log.Error("TODO") return nil, errTODO @@ -875,6 +969,9 @@ func (c *Client) AuctionSetClosedAuctionSlots(newClosedAuctionSlots uint16) (tx defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } log.Error("TODO") return nil, errTODO @@ -895,6 +992,9 @@ func (c *Client) AuctionSetOutbidding(newOutbidding uint16) (tx *types.Transacti defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } log.Error("TODO") return nil, errTODO @@ -915,6 +1015,9 @@ func (c *Client) AuctionSetAllocationRatio(newAllocationRatio [3]uint16) (tx *ty defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } log.Error("TODO") return nil, errTODO @@ -935,6 +1038,9 @@ func (c *Client) AuctionSetDonationAddress(newDonationAddress ethCommon.Address) defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } log.Error("TODO") return nil, errTODO @@ -955,6 +1061,9 @@ func (c *Client) AuctionSetBootCoordinator(newBootCoordinator ethCommon.Address) defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } log.Error("TODO") return nil, errTODO @@ -977,6 +1086,9 @@ func (c *Client) AuctionChangeDefaultSlotSetBid(slotSet int64, newInitialMinBid defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } log.Error("TODO") return nil, errTODO @@ -988,6 +1100,9 @@ func (c *Client) AuctionRegisterCoordinator(forgerAddress ethCommon.Address, URL defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } nextBlock := c.nextBlock() a := nextBlock.Auction @@ -996,14 +1111,14 @@ func (c *Client) AuctionRegisterCoordinator(forgerAddress ethCommon.Address, URL return nil, fmt.Errorf("Already registered") } a.State.Coordinators[forgerAddress] = ð.Coordinator{ - WithdrawalAddress: c.addr, + WithdrawalAddress: *c.addr, URL: URL, } a.Events.NewCoordinator = append(a.Events.NewCoordinator, eth.AuctionEventNewCoordinator{ ForgerAddress: forgerAddress, - WithdrawalAddress: c.addr, + WithdrawalAddress: *c.addr, CoordinatorURL: URL, }) @@ -1011,7 +1126,7 @@ func (c *Client) AuctionRegisterCoordinator(forgerAddress ethCommon.Address, URL ForgerAddress ethCommon.Address URL string } - return c.newTransaction("registercoordinator", data{forgerAddress, URL}), nil + return a.addTransaction(newTransaction("registercoordinator", data{forgerAddress, URL})), nil } // AuctionIsRegisteredCoordinator is the interface to call the smart contract function @@ -1029,11 +1144,24 @@ func (c *Client) AuctionUpdateCoordinatorInfo(forgerAddress ethCommon.Address, n defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } log.Error("TODO") return nil, errTODO } +// AuctionGetSlotNumber is the interface to call the smart contract function +func (c *Client) AuctionGetSlotNumber(blockNum int64) (int64, error) { + c.rw.RLock() + defer c.rw.RUnlock() + + currentBlock := c.currentBlock() + a := currentBlock.Auction + return a.getSlotNumber(blockNum), nil +} + // AuctionGetCurrentSlotNumber is the interface to call the smart contract function func (c *Client) AuctionGetCurrentSlotNumber() (int64, error) { c.rw.RLock() @@ -1070,15 +1198,6 @@ func (c *Client) AuctionGetSlotSet(slot int64) (*big.Int, error) { return nil, errTODO } -// AuctionGetSlotNumber is the interface to call the smart contract function -func (c *Client) AuctionGetSlotNumber(blockNum int64) (*big.Int, error) { - c.rw.RLock() - defer c.rw.RUnlock() - - log.Error("TODO") - return nil, errTODO -} - // AuctionTokensReceived is the interface to call the smart contract function // func (c *Client) AuctionTokensReceived(operator, from, to ethCommon.Address, amount *big.Int, userData, operatorData []byte) error { // return errTODO @@ -1090,6 +1209,9 @@ func (c *Client) AuctionBid(slot int64, bidAmount *big.Int, forger ethCommon.Add defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { func() { c.revertIfErr(err, cpy) }() }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } nextBlock := c.nextBlock() a := nextBlock.Auction @@ -1130,7 +1252,7 @@ func (c *Client) AuctionBid(slot int64, bidAmount *big.Int, forger ethCommon.Add BidAmount *big.Int Forger ethCommon.Address } - return c.newTransaction("bid", data{slot, bidAmount, forger}), nil + return a.addTransaction(newTransaction("bid", data{slot, bidAmount, forger})), nil } // AuctionMultiBid is the interface to call the smart contract function @@ -1139,6 +1261,9 @@ func (c *Client) AuctionMultiBid(startingSlot int64, endingSlot int64, slotSet [ defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } log.Error("TODO") return nil, errTODO @@ -1165,6 +1290,9 @@ func (c *Client) AuctionClaimHEZ(claimAddress ethCommon.Address) (tx *types.Tran defer c.rw.Unlock() cpy := c.nextBlock().copy() defer func() { c.revertIfErr(err, cpy) }() + if c.addr == nil { + return nil, eth.ErrAccountNil + } log.Error("TODO") return nil, errTODO diff --git a/test/ethclient_test.go b/test/ethclient_test.go index afe3ce0..9e7ddb3 100644 --- a/test/ethclient_test.go +++ b/test/ethclient_test.go @@ -31,7 +31,7 @@ func TestClientInterface(t *testing.T) { var c eth.ClientInterface var timer timer clientSetup := NewClientSetupExample() - client := NewClient(true, &timer, ethCommon.Address{}, clientSetup) + client := NewClient(true, &timer, ðCommon.Address{}, clientSetup) c = client require.NotNil(t, c) } @@ -39,7 +39,7 @@ func TestClientInterface(t *testing.T) { func TestClientEth(t *testing.T) { var timer timer clientSetup := NewClientSetupExample() - c := NewClient(true, &timer, ethCommon.Address{}, clientSetup) + c := NewClient(true, &timer, ðCommon.Address{}, clientSetup) blockNum, err := c.EthCurrentBlock() require.Nil(t, err) assert.Equal(t, int64(0), blockNum) @@ -76,7 +76,7 @@ func TestClientAuction(t *testing.T) { clientSetup.AuctionVariables.DefaultSlotSetBid = [6]*big.Int{ big.NewInt(1000), big.NewInt(1100), big.NewInt(1200), big.NewInt(1300), big.NewInt(1400), big.NewInt(1500)} - c := NewClient(true, &timer, addrWithdraw, clientSetup) + c := NewClient(true, &timer, &addrWithdraw, clientSetup) // Check several cases in which bid doesn't succed, and also do 2 successful bids. @@ -124,7 +124,7 @@ func TestClientRollup(t *testing.T) { var timer timer clientSetup := NewClientSetupExample() - c := NewClient(true, &timer, ethCommon.Address{}, clientSetup) + c := NewClient(true, &timer, ðCommon.Address{}, clientSetup) // Add a token