From 42791181a1dc050b5a88be42a82f21a0218983c4 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Tue, 29 Dec 2020 17:21:45 +0100 Subject: [PATCH] Load ethereum private key Load an ethereum keystore when the node is started in coordinator mode. The private key corresponding to the forger address must be imported into the keystore before running the node in coordinator mode. You can see an examples in `cli/node/load-sk-example.sh`. --- cli/node/cfg.buidler.toml | 10 +++- cli/node/load-sk-example.sh | 7 +++ cli/node/main.go | 48 ++++++++++++++--- config/config.go | 7 +++ coordinator/coordinator.go | 66 ++++++++++++++---------- coordinator/coordinator_test.go | 91 ++++++++++++++++++++++++++++++--- db/statedb/statedb_test.go | 4 ++ eth/client.go | 5 +- eth/ethereum.go | 14 +++-- eth/ethereum_test.go | 3 +- eth/main_test.go | 25 +++++++-- node/node.go | 29 ++++++++++- 12 files changed, 253 insertions(+), 56 deletions(-) create mode 100755 cli/node/load-sk-example.sh diff --git a/cli/node/cfg.buidler.toml b/cli/node/cfg.buidler.toml index e45a14d..b7cb0c0 100644 --- a/cli/node/cfg.buidler.toml +++ b/cli/node/cfg.buidler.toml @@ -38,7 +38,8 @@ TokenHEZ = "0x5D94e3e7aeC542aB0F9129B9a7BAdeb5B3Ca0f77" TokenHEZName = "Hermez Network Token" [Coordinator] -ForgerAddress = "0x6BB84Cc84D4A34467aD12a2039A312f7029e2071" +# ForgerAddress = "0x05c23b938a85ab26A36E6314a0D02080E9ca6BeD" # Non-Boot Coordinator +ForgerAddress = "0xb4124ceb3451635dacedd11767f004d8a28c6ee7" # Boot Coordinator ConfirmBlocks = 10 L1BatchTimeoutPerc = 0.6 ProofServerPollInterval = "1s" @@ -60,7 +61,7 @@ Path = "/tmp/iden3-test/hermez/txselector" Path = "/tmp/iden3-test/hermez/batchbuilder" [[Coordinator.ServerProofs]] -URL = "http://localhost:3000" +URL = "http://localhost:3000/api" [Coordinator.EthClient] CallGasLimit = 300000 @@ -73,8 +74,13 @@ CheckLoopInterval = "500ms" Attempts = 8 AttemptsDelay = "200ms" +[Coordinator.EthClient.Keystore] +Path = "/tmp/iden3-test/hermez/ethkeystore" +Password = "yourpasswordhere" + [Coordinator.API] Coordinator = true [Coordinator.Debug] BatchPath = "/tmp/iden3-test/hermez/batchesdebug" +LightScrypt = true diff --git a/cli/node/load-sk-example.sh b/cli/node/load-sk-example.sh new file mode 100755 index 0000000..bfaaff2 --- /dev/null +++ b/cli/node/load-sk-example.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +# Non-Boot Coordinator +go run . --mode coord --cfg cfg.buidler.toml importkey --privatekey 0x30f5fddb34cd4166adb2c6003fa6b18f380fd2341376be42cf1c7937004ac7a3 + +# Boot Coordinator +go run . --mode coord --cfg cfg.buidler.toml importkey --privatekey 0xa8a54b2d8197bc0b19bb8a084031be71835580a01e70a45a13babd16c9bc1563 diff --git a/cli/node/main.go b/cli/node/main.go index 833ac3c..92513a2 100644 --- a/cli/node/main.go +++ b/cli/node/main.go @@ -4,7 +4,10 @@ import ( "fmt" "os" "os/signal" + "strings" + ethKeystore "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/crypto" "github.com/hermeznetwork/hermez-node/config" "github.com/hermeznetwork/hermez-node/log" "github.com/hermeznetwork/hermez-node/node" @@ -15,18 +18,41 @@ import ( const ( flagCfg = "cfg" flagMode = "mode" + flagSK = "privatekey" modeSync = "sync" modeCoord = "coord" ) -func cmdInit(c *cli.Context) error { - log.Info("Init") - cfg, err := parseCli(c) +func cmdImportKey(c *cli.Context) error { + _cfg, err := parseCli(c) + if err != nil { + return tracerr.Wrap(fmt.Errorf("error parsing flags and config: %w", err)) + } + if _cfg.mode != node.ModeCoordinator { + return tracerr.Wrap(fmt.Errorf("importkey must use mode coordinator")) + } + cfg := _cfg.node + + scryptN := ethKeystore.StandardScryptN + scryptP := ethKeystore.StandardScryptP + if cfg.Coordinator.Debug.LightScrypt { + scryptN = ethKeystore.LightScryptN + scryptP = ethKeystore.LightScryptP + } + keyStore := ethKeystore.NewKeyStore(cfg.Coordinator.EthClient.Keystore.Path, + scryptN, scryptP) + hexKey := c.String(flagSK) + hexKey = strings.TrimPrefix(hexKey, "0x") + sk, err := crypto.HexToECDSA(hexKey) if err != nil { return tracerr.Wrap(err) } - fmt.Println("TODO", cfg) - return tracerr.Wrap(err) + acc, err := keyStore.ImportECDSA(sk, cfg.Coordinator.EthClient.Keystore.Password) + if err != nil { + return tracerr.Wrap(err) + } + log.Infow("Imported private key", "addr", acc.Address.Hex()) + return nil } func cmdRun(c *cli.Context) error { @@ -122,10 +148,16 @@ func main() { app.Commands = []*cli.Command{ { - Name: "init", + Name: "importkey", Aliases: []string{}, - Usage: "Initialize the hermez-node", - Action: cmdInit, + Usage: "Import ethereum private key", + Action: cmdImportKey, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: flagSK, + Usage: "ethereum `PRIVATE_KEY` in hex", + Required: true, + }}, }, { Name: "run", diff --git a/config/config.go b/config/config.go index 42e79da..0c63a0e 100644 --- a/config/config.go +++ b/config/config.go @@ -83,6 +83,10 @@ type Coordinator struct { // AttemptsDelay is delay between attempts do do an eth client // RPC call AttemptsDelay Duration `validate:"required"` + Keystore struct { + Path string `validate:"required"` + Password string `validate:"required"` + } `validate:"required"` } `validate:"required"` API struct { Coordinator bool @@ -91,6 +95,9 @@ type Coordinator struct { // BatchPath if set, specifies the path where batchInfo is stored // in JSON in every step/update of the pipeline BatchPath string + // LightScrypt if set, uses light parameters for the ethereum + // keystore encryption algorithm. + LightScrypt bool } } diff --git a/coordinator/coordinator.go b/coordinator/coordinator.go index 9f078d7..b10e229 100644 --- a/coordinator/coordinator.go +++ b/coordinator/coordinator.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "math/big" + "os" "strings" "sync" "time" @@ -111,6 +112,12 @@ func NewCoordinator(cfg Config, cfg.EthClientAttempts)) } + if cfg.DebugBatchPath != "" { + if err := os.MkdirAll(cfg.DebugBatchPath, 0744); err != nil { + return nil, tracerr.Wrap(err) + } + } + purger := Purger{ cfg: cfg.Purger, lastPurgeBlock: 0, @@ -147,9 +154,10 @@ func NewCoordinator(cfg Config, return &c, nil } -func (c *Coordinator) newPipeline(ctx context.Context) (*Pipeline, error) { +func (c *Coordinator) newPipeline(ctx context.Context, + stats *synchronizer.Stats) (*Pipeline, error) { return NewPipeline(ctx, c.cfg, c.historyDB, c.l2DB, c.txSelector, - c.batchBuilder, c.purger, c.txManager, c.provers, &c.consts) + c.batchBuilder, c.purger, c.txManager, c.provers, stats, &c.consts) } // MsgSyncBlock indicates an update to the Synchronizer stats @@ -226,7 +234,7 @@ func (c *Coordinator) syncStats(ctx context.Context, stats *synchronizer.Stats) stats.Eth.LastBlock.Num, "batch", stats.Sync.LastBatch) batchNum := common.BatchNum(stats.Sync.LastBatch) var err error - if c.pipeline, err = c.newPipeline(ctx); err != nil { + if c.pipeline, err = c.newPipeline(ctx, stats); err != nil { return tracerr.Wrap(err) } if err := c.pipeline.Start(batchNum, stats.Sync.LastForgeL1TxsNum, @@ -295,22 +303,16 @@ func (c *Coordinator) handleStopPipeline(ctx context.Context, reason string) err func (c *Coordinator) handleMsg(ctx context.Context, msg interface{}) error { switch msg := msg.(type) { case MsgSyncBlock: - if err := c.handleMsgSyncBlock(ctx, &msg); common.IsErrDone(err) { - return nil - } else if err != nil { + if err := c.handleMsgSyncBlock(ctx, &msg); err != nil { return tracerr.Wrap(fmt.Errorf("Coordinator.handleMsgSyncBlock error: %w", err)) } case MsgSyncReorg: - if err := c.handleReorg(ctx, &msg.Stats); common.IsErrDone(err) { - return nil - } else if err != nil { + if err := c.handleReorg(ctx, &msg.Stats); err != nil { return tracerr.Wrap(fmt.Errorf("Coordinator.handleReorg error: %w", err)) } case MsgStopPipeline: log.Infow("Coordinator received MsgStopPipeline", "reason", msg.Reason) - if err := c.handleStopPipeline(ctx, msg.Reason); common.IsErrDone(err) { - return nil - } else if err != nil { + if err := c.handleStopPipeline(ctx, msg.Reason); err != nil { return tracerr.Wrap(fmt.Errorf("Coordinator.handleStopPipeline: %w", err)) } default: @@ -341,7 +343,9 @@ func (c *Coordinator) Start() { c.wg.Done() return case msg := <-c.msgCh: - if err := c.handleMsg(c.ctx, msg); err != nil { + if err := c.handleMsg(c.ctx, msg); c.ctx.Err() != nil { + continue + } else if err != nil { log.Errorw("Coordinator.handleMsg", "err", err) waitDuration = time.Duration(c.cfg.SyncRetryInterval) continue @@ -352,7 +356,9 @@ func (c *Coordinator) Start() { waitDuration = time.Duration(longWaitDuration) continue } - if err := c.syncStats(c.ctx, c.stats); 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) waitDuration = time.Duration(c.cfg.SyncRetryInterval) continue @@ -456,7 +462,8 @@ func (t *TxManager) rollupForgeBatch(ctx context.Context, batchInfo *BatchInfo) return tracerr.Wrap(err) } log.Errorw("TxManager ethClient.RollupForgeBatch", - "attempt", attempt, "err", err, "block", t.lastBlock) + "attempt", attempt, "err", err, "block", t.lastBlock, + "batchNum", batchInfo.BatchNum) } else { break } @@ -484,6 +491,9 @@ func (t *TxManager) ethTransactionReceipt(ctx context.Context, batchInfo *BatchI var err error for attempt := 0; attempt < t.cfg.EthClientAttempts; attempt++ { receipt, err = t.ethClient.EthTransactionReceipt(ctx, txHash) + if ctx.Err() != nil { + continue + } if err != nil { log.Errorw("TxManager ethClient.EthTransactionReceipt", "attempt", attempt, "err", err) @@ -621,6 +631,7 @@ func NewPipeline(ctx context.Context, purger *Purger, txManager *TxManager, provers []prover.Client, + stats *synchronizer.Stats, scConsts *synchronizer.SCConsts, ) (*Pipeline, error) { proversPool := NewProversPool(len(provers)) @@ -647,6 +658,7 @@ func NewPipeline(ctx context.Context, purger: purger, txManager: txManager, consts: *scConsts, + stats: *stats, statsCh: make(chan synchronizer.Stats, queueLen), }, nil } @@ -697,7 +709,7 @@ func (p *Pipeline) Start(batchNum common.BatchNum, lastForgeL1TxsNum int64, for { select { case <-p.ctx.Done(): - log.Debug("Pipeline forgeBatch loop done") + log.Info("Pipeline forgeBatch loop done") p.wg.Done() return case syncStats := <-p.statsCh: @@ -705,7 +717,7 @@ func (p *Pipeline) Start(batchNum common.BatchNum, lastForgeL1TxsNum int64, default: batchNum = p.batchNum + 1 batchInfo, err := p.forgeBatch(p.ctx, batchNum, selectionConfig) - if common.IsErrDone(err) { + if p.ctx.Err() != nil { continue } else if err != nil { log.Errorw("forgeBatch", "err", err) @@ -713,14 +725,16 @@ func (p *Pipeline) Start(batchNum common.BatchNum, lastForgeL1TxsNum int64, } // 6. Wait for an available server proof (blocking call) serverProof, err := p.proversPool.Get(p.ctx) - if common.IsErrDone(err) { + if p.ctx.Err() != nil { continue } else if err != nil { log.Errorw("proversPool.Get", "err", err) continue } batchInfo.ServerProof = serverProof - if err := p.sendServerProof(p.ctx, batchInfo); err != nil { + if err := p.sendServerProof(p.ctx, batchInfo); p.ctx.Err() != nil { + continue + } else if err != nil { log.Errorw("sendServerProof", "err", err) batchInfo.ServerProof = nil p.proversPool.Add(serverProof) @@ -737,17 +751,17 @@ func (p *Pipeline) Start(batchNum common.BatchNum, lastForgeL1TxsNum int64, for { select { case <-p.ctx.Done(): - log.Debug("Pipeline waitServerProofSendEth loop done") + log.Info("Pipeline waitServerProofSendEth loop done") p.wg.Done() return case batchInfo := <-batchChSentServerProof: err := p.waitServerProof(p.ctx, batchInfo) - if common.IsErrDone(err) { - continue - } // We are done with this serverProof, add it back to the pool p.proversPool.Add(batchInfo.ServerProof) batchInfo.ServerProof = nil + if p.ctx.Err() != nil { + continue + } if err != nil { log.Errorw("waitServerProof", "err", err) continue @@ -765,7 +779,7 @@ func (p *Pipeline) Stop(ctx context.Context) { log.Fatal("Pipeline already stopped") } p.started = false - log.Debug("Stopping Pipeline...") + log.Info("Stopping Pipeline...") p.cancel() p.wg.Wait() for _, prover := range p.provers { @@ -899,7 +913,7 @@ func (p *Pipeline) waitServerProof(ctx context.Context, batchInfo *BatchInfo) er } batchInfo.Proof = proof batchInfo.PublicInputs = pubInputs - batchInfo.ForgeBatchArgs = p.prepareForgeBatchArgs(batchInfo) + batchInfo.ForgeBatchArgs = prepareForgeBatchArgs(batchInfo) batchInfo.TxStatus = TxStatusPending p.cfg.debugBatchStore(batchInfo) return nil @@ -921,7 +935,7 @@ func (p *Pipeline) shouldL1L2Batch() bool { return false } -func (p *Pipeline) prepareForgeBatchArgs(batchInfo *BatchInfo) *eth.RollupForgeBatchArgs { +func prepareForgeBatchArgs(batchInfo *BatchInfo) *eth.RollupForgeBatchArgs { proof := batchInfo.Proof zki := batchInfo.ZKInputs return ð.RollupForgeBatchArgs{ diff --git a/coordinator/coordinator_test.go b/coordinator/coordinator_test.go index 16cfcc9..21fa24a 100644 --- a/coordinator/coordinator_test.go +++ b/coordinator/coordinator_test.go @@ -10,7 +10,10 @@ import ( "testing" "time" + ethKeystore "github.com/ethereum/go-ethereum/accounts/keystore" ethCommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" "github.com/hermeznetwork/hermez-node/batchbuilder" "github.com/hermeznetwork/hermez-node/common" dbUtils "github.com/hermeznetwork/hermez-node/db" @@ -26,6 +29,7 @@ import ( "github.com/hermeznetwork/hermez-node/txprocessor" "github.com/hermeznetwork/hermez-node/txselector" "github.com/hermeznetwork/tracerr" + "github.com/iden3/go-merkletree" "github.com/iden3/go-merkletree/db/pebble" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -428,8 +432,9 @@ func TestPipelineShouldL1L2Batch(t *testing.T) { ctx := context.Background() ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup) modules := newTestModules(t) + var stats synchronizer.Stats coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules) - pipeline, err := coord.newPipeline(ctx) + pipeline, err := coord.newPipeline(ctx, &stats) require.NoError(t, err) pipeline.vars = coord.vars @@ -439,8 +444,6 @@ func TestPipelineShouldL1L2Batch(t *testing.T) { l1BatchTimeoutPerc := pipeline.cfg.L1BatchTimeoutPerc l1BatchTimeout := ethClientSetup.RollupVariables.ForgeL1L2BatchTimeout - var stats synchronizer.Stats - startBlock := int64(100) // @@ -576,11 +579,6 @@ func TestPipeline1(t *testing.T) { modules := newTestModules(t) coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules) sync := newTestSynchronizer(t, ethClient, ethClientSetup, modules) - pipeline, err := coord.newPipeline(ctx) - require.NoError(t, err) - - require.NotNil(t, sync) - require.NotNil(t, pipeline) // preload the synchronier (via the test ethClient) some tokens and // users with positive balances @@ -589,6 +587,9 @@ func TestPipeline1(t *testing.T) { batchNum := common.BatchNum(syncStats.Sync.LastBatch) syncSCVars := sync.SCVars() + pipeline, err := coord.newPipeline(ctx, syncStats) + require.NoError(t, err) + // Insert some l2txs in the Pool setPool := ` Type: PoolL2 @@ -713,6 +714,80 @@ func TestCoordinatorStress(t *testing.T) { coord.Stop() } +func TestRollupForgeBatch(t *testing.T) { + if os.Getenv("TEST_ROLLUP_FORGE_BATCH") == "" { + return + } + const web3URL = "http://localhost:8545" + const password = "test" + addr := ethCommon.HexToAddress("0xb4124ceb3451635dacedd11767f004d8a28c6ee7") + sk, err := crypto.HexToECDSA( + "a8a54b2d8197bc0b19bb8a084031be71835580a01e70a45a13babd16c9bc1563") + require.NoError(t, err) + rollupAddr := ethCommon.HexToAddress("0x8EEaea23686c319133a7cC110b840d1591d9AeE0") + pathKeystore, err := ioutil.TempDir("", "tmpKeystore") + require.NoError(t, err) + deleteme = append(deleteme, pathKeystore) + ctx := context.Background() + batchInfo := &BatchInfo{} + proofClient := &prover.MockClient{} + chainID := uint16(0) + + ethClient, err := ethclient.Dial(web3URL) + require.NoError(t, err) + ethCfg := eth.EthereumConfig{ + CallGasLimit: 300000, + DeployGasLimit: 1000000, + GasPriceDiv: 100, + ReceiptTimeout: 60 * time.Second, + IntervalReceiptLoop: 500 * time.Millisecond, + } + scryptN := ethKeystore.LightScryptN + scryptP := ethKeystore.LightScryptP + keyStore := ethKeystore.NewKeyStore(pathKeystore, + scryptN, scryptP) + account, err := keyStore.ImportECDSA(sk, password) + require.NoError(t, err) + require.Equal(t, account.Address, addr) + err = keyStore.Unlock(account, password) + require.NoError(t, err) + + client, err := eth.NewClient(ethClient, &account, keyStore, ð.ClientConfig{ + Ethereum: ethCfg, + Rollup: eth.RollupConfig{ + Address: rollupAddr, + }, + Auction: eth.AuctionConfig{ + Address: ethCommon.Address{}, + TokenHEZ: eth.TokenConfig{ + Address: ethCommon.Address{}, + Name: "HEZ", + }, + }, + WDelayer: eth.WDelayerConfig{ + Address: ethCommon.Address{}, + }, + }) + require.NoError(t, err) + + zkInputs := common.NewZKInputs(chainID, 100, 24, 512, 32, big.NewInt(1)) + zkInputs.Metadata.NewStateRootRaw = &merkletree.Hash{1} + zkInputs.Metadata.NewExitRootRaw = &merkletree.Hash{2} + batchInfo.ZKInputs = zkInputs + err = proofClient.CalculateProof(ctx, batchInfo.ZKInputs) + require.NoError(t, err) + + proof, pubInputs, err := proofClient.GetProof(ctx) + require.NoError(t, err) + batchInfo.Proof = proof + batchInfo.PublicInputs = pubInputs + + batchInfo.ForgeBatchArgs = prepareForgeBatchArgs(batchInfo) + _, err = client.RollupForgeBatch(batchInfo.ForgeBatchArgs) + require.NoError(t, err) + batchInfo.Proof = proof +} + // TODO: Test Reorg // TODO: Test Pipeline // TODO: Test TxMonitor diff --git a/db/statedb/statedb_test.go b/db/statedb/statedb_test.go index f9a41ca..d1d8412 100644 --- a/db/statedb/statedb_test.go +++ b/db/statedb/statedb_test.go @@ -112,6 +112,10 @@ func TestNewStateDBIntermediateState(t *testing.T) { sdb, err = NewStateDB(dir, 128, TypeTxSelector, 0) assert.NoError(t, err) + bn, err = sdb.db.GetCurrentBatch() + assert.NoError(t, err) + assert.Equal(t, common.BatchNum(1), bn) + v, err = sdb.db.DB().Get(k0) assert.NoError(t, err) assert.Equal(t, v0, v) diff --git a/eth/client.go b/eth/client.go index 4401b0d..f86fccf 100644 --- a/eth/client.go +++ b/eth/client.go @@ -65,7 +65,10 @@ type ClientConfig struct { // NewClient creates a new Client to interact with Ethereum and the Hermez smart contracts. func NewClient(client *ethclient.Client, account *accounts.Account, ks *ethKeystore.KeyStore, cfg *ClientConfig) (*Client, error) { - ethereumClient := NewEthereumClient(client, account, ks, &cfg.Ethereum) + ethereumClient, err := NewEthereumClient(client, account, ks, &cfg.Ethereum) + if err != nil { + return nil, tracerr.Wrap(err) + } auctionClient, err := NewAuctionClient(ethereumClient, cfg.Auction.Address, cfg.Auction.TokenHEZ) if err != nil { return nil, tracerr.Wrap(err) diff --git a/eth/ethereum.go b/eth/ethereum.go index 4327307..d2b2426 100644 --- a/eth/ethereum.go +++ b/eth/ethereum.go @@ -73,6 +73,7 @@ type EthereumConfig struct { // EthereumClient is an ethereum client to call Smart Contract methods and check blockchain information. type EthereumClient struct { client *ethclient.Client + chainID *big.Int account *accounts.Account ks *ethKeystore.KeyStore ReceiptTimeout time.Duration @@ -82,7 +83,7 @@ type EthereumClient struct { // NewEthereumClient creates a EthereumClient instance. The account is not mandatory (it can // be nil). If the account is nil, CallAuth will fail with ErrAccountNil. -func NewEthereumClient(client *ethclient.Client, account *accounts.Account, ks *ethKeystore.KeyStore, config *EthereumConfig) *EthereumClient { +func NewEthereumClient(client *ethclient.Client, account *accounts.Account, ks *ethKeystore.KeyStore, config *EthereumConfig) (*EthereumClient, error) { if config == nil { config = &EthereumConfig{ CallGasLimit: defaultCallGasLimit, @@ -92,7 +93,7 @@ func NewEthereumClient(client *ethclient.Client, account *accounts.Account, ks * IntervalReceiptLoop: defaultIntervalReceiptLoop, } } - return &EthereumClient{ + c := &EthereumClient{ client: client, account: account, ks: ks, @@ -100,6 +101,12 @@ func NewEthereumClient(client *ethclient.Client, account *accounts.Account, ks * config: config, opts: newCallOpts(), } + chainID, err := c.EthChainID() + if err != nil { + return nil, tracerr.Wrap(err) + } + c.chainID = chainID + return c, nil } // EthChainID returns the ChainID of the ethereum network @@ -147,8 +154,7 @@ func (c *EthereumClient) CallAuth(gasLimit uint64, gasPrice.Add(gasPrice, inc) log.Debugw("Transaction metadata", "gasPrice", gasPrice) - // TODO: Set the correct chainID - auth, err := bind.NewKeyStoreTransactorWithChainID(c.ks, *c.account, big.NewInt(0)) + auth, err := bind.NewKeyStoreTransactorWithChainID(c.ks, *c.account, c.chainID) if err != nil { return nil, tracerr.Wrap(err) } diff --git a/eth/ethereum_test.go b/eth/ethereum_test.go index 5162344..1813894 100644 --- a/eth/ethereum_test.go +++ b/eth/ethereum_test.go @@ -11,7 +11,8 @@ import ( func TestEthERC20(t *testing.T) { ethClient, err := ethclient.Dial(ethClientDialURL) require.Nil(t, err) - client := NewEthereumClient(ethClient, auxAccount, ks, nil) + client, err := NewEthereumClient(ethClient, auxAccount, ks, nil) + require.Nil(t, err) consts, err := client.EthERC20Consts(tokenHEZAddressConst) require.Nil(t, err) diff --git a/eth/main_test.go b/eth/main_test.go index 9b0242a..d04f879 100644 --- a/eth/main_test.go +++ b/eth/main_test.go @@ -164,7 +164,10 @@ func TestMain(m *testing.M) { } // Controllable Governance Address - ethereumClientGov := NewEthereumClient(ethClient, governanceAccount, ks, nil) + ethereumClientGov, err := NewEthereumClient(ethClient, governanceAccount, ks, nil) + if err != nil { + log.Fatal(err) + } auctionClient, err = NewAuctionClient(ethereumClientGov, auctionAddressConst, tokenHEZ) if err != nil { log.Fatal(err) @@ -186,10 +189,22 @@ func TestMain(m *testing.M) { log.Fatal(err) } - ethereumClientEmergencyCouncil = NewEthereumClient(ethClient, emergencyCouncilAccount, ks, nil) - ethereumClientAux = NewEthereumClient(ethClient, auxAccount, ks, nil) - ethereumClientAux2 = NewEthereumClient(ethClient, aux2Account, ks, nil) - ethereumClientHermez = NewEthereumClient(ethClient, hermezRollupTestAccount, ks, nil) + ethereumClientEmergencyCouncil, err = NewEthereumClient(ethClient, emergencyCouncilAccount, ks, nil) + if err != nil { + log.Fatal(err) + } + ethereumClientAux, err = NewEthereumClient(ethClient, auxAccount, ks, nil) + if err != nil { + log.Fatal(err) + } + ethereumClientAux2, err = NewEthereumClient(ethClient, aux2Account, ks, nil) + if err != nil { + log.Fatal(err) + } + ethereumClientHermez, err = NewEthereumClient(ethClient, hermezRollupTestAccount, ks, nil) + if err != nil { + log.Fatal(err) + } exitVal = m.Run() } diff --git a/node/node.go b/node/node.go index 0a3df78..1d21c7b 100644 --- a/node/node.go +++ b/node/node.go @@ -7,6 +7,8 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/accounts" + ethKeystore "github.com/ethereum/go-ethereum/accounts/keystore" ethCommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/gin-contrib/cors" @@ -87,6 +89,8 @@ func NewNode(mode Mode, cfg *config.Node) (*Node, error) { return nil, tracerr.Wrap(err) } var ethCfg eth.EthereumConfig + var account *accounts.Account + var keyStore *ethKeystore.KeyStore if mode == ModeCoordinator { ethCfg = eth.EthereumConfig{ CallGasLimit: cfg.Coordinator.EthClient.CallGasLimit, @@ -95,8 +99,31 @@ func NewNode(mode Mode, cfg *config.Node) (*Node, error) { ReceiptTimeout: cfg.Coordinator.EthClient.ReceiptTimeout.Duration, IntervalReceiptLoop: cfg.Coordinator.EthClient.ReceiptLoopInterval.Duration, } + + scryptN := ethKeystore.StandardScryptN + scryptP := ethKeystore.StandardScryptP + if cfg.Coordinator.Debug.LightScrypt { + scryptN = ethKeystore.LightScryptN + scryptP = ethKeystore.LightScryptP + } + keyStore = ethKeystore.NewKeyStore(cfg.Coordinator.EthClient.Keystore.Path, + scryptN, scryptP) + if !keyStore.HasAddress(cfg.Coordinator.ForgerAddress) { + return nil, tracerr.Wrap(fmt.Errorf( + "ethereum keystore doesn't have the key for address %v", + cfg.Coordinator.ForgerAddress)) + } + account = &accounts.Account{ + Address: cfg.Coordinator.ForgerAddress, + } + if err := keyStore.Unlock(*account, + cfg.Coordinator.EthClient.Keystore.Password); err != nil { + return nil, tracerr.Wrap(err) + } + log.Infow("Forger ethereum account unlocked in the keystore", + "addr", cfg.Coordinator.ForgerAddress) } - client, err := eth.NewClient(ethClient, nil, nil, ð.ClientConfig{ + client, err := eth.NewClient(ethClient, account, keyStore, ð.ClientConfig{ Ethereum: ethCfg, Rollup: eth.RollupConfig{ Address: cfg.SmartContracts.Rollup,