Browse Source

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`.
feature/sql-semaphore1
Eduard S 3 years ago
parent
commit
42791181a1
12 changed files with 253 additions and 56 deletions
  1. +8
    -2
      cli/node/cfg.buidler.toml
  2. +7
    -0
      cli/node/load-sk-example.sh
  3. +40
    -8
      cli/node/main.go
  4. +7
    -0
      config/config.go
  5. +40
    -26
      coordinator/coordinator.go
  6. +83
    -8
      coordinator/coordinator_test.go
  7. +4
    -0
      db/statedb/statedb_test.go
  8. +4
    -1
      eth/client.go
  9. +10
    -4
      eth/ethereum.go
  10. +2
    -1
      eth/ethereum_test.go
  11. +20
    -5
      eth/main_test.go
  12. +28
    -1
      node/node.go

+ 8
- 2
cli/node/cfg.buidler.toml

@ -38,7 +38,8 @@ TokenHEZ = "0x5D94e3e7aeC542aB0F9129B9a7BAdeb5B3Ca0f77"
TokenHEZName = "Hermez Network Token" TokenHEZName = "Hermez Network Token"
[Coordinator] [Coordinator]
ForgerAddress = "0x6BB84Cc84D4A34467aD12a2039A312f7029e2071"
# ForgerAddress = "0x05c23b938a85ab26A36E6314a0D02080E9ca6BeD" # Non-Boot Coordinator
ForgerAddress = "0xb4124ceb3451635dacedd11767f004d8a28c6ee7" # Boot Coordinator
ConfirmBlocks = 10 ConfirmBlocks = 10
L1BatchTimeoutPerc = 0.6 L1BatchTimeoutPerc = 0.6
ProofServerPollInterval = "1s" ProofServerPollInterval = "1s"
@ -60,7 +61,7 @@ Path = "/tmp/iden3-test/hermez/txselector"
Path = "/tmp/iden3-test/hermez/batchbuilder" Path = "/tmp/iden3-test/hermez/batchbuilder"
[[Coordinator.ServerProofs]] [[Coordinator.ServerProofs]]
URL = "http://localhost:3000"
URL = "http://localhost:3000/api"
[Coordinator.EthClient] [Coordinator.EthClient]
CallGasLimit = 300000 CallGasLimit = 300000
@ -73,8 +74,13 @@ CheckLoopInterval = "500ms"
Attempts = 8 Attempts = 8
AttemptsDelay = "200ms" AttemptsDelay = "200ms"
[Coordinator.EthClient.Keystore]
Path = "/tmp/iden3-test/hermez/ethkeystore"
Password = "yourpasswordhere"
[Coordinator.API] [Coordinator.API]
Coordinator = true Coordinator = true
[Coordinator.Debug] [Coordinator.Debug]
BatchPath = "/tmp/iden3-test/hermez/batchesdebug" BatchPath = "/tmp/iden3-test/hermez/batchesdebug"
LightScrypt = true

+ 7
- 0
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

+ 40
- 8
cli/node/main.go

@ -4,7 +4,10 @@ import (
"fmt" "fmt"
"os" "os"
"os/signal" "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/config"
"github.com/hermeznetwork/hermez-node/log" "github.com/hermeznetwork/hermez-node/log"
"github.com/hermeznetwork/hermez-node/node" "github.com/hermeznetwork/hermez-node/node"
@ -15,18 +18,41 @@ import (
const ( const (
flagCfg = "cfg" flagCfg = "cfg"
flagMode = "mode" flagMode = "mode"
flagSK = "privatekey"
modeSync = "sync" modeSync = "sync"
modeCoord = "coord" 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 { if err != nil {
return tracerr.Wrap(err) 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 { func cmdRun(c *cli.Context) error {
@ -122,10 +148,16 @@ func main() {
app.Commands = []*cli.Command{ app.Commands = []*cli.Command{
{ {
Name: "init",
Name: "importkey",
Aliases: []string{}, 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", Name: "run",

+ 7
- 0
config/config.go

@ -83,6 +83,10 @@ type Coordinator struct {
// AttemptsDelay is delay between attempts do do an eth client // AttemptsDelay is delay between attempts do do an eth client
// RPC call // RPC call
AttemptsDelay Duration `validate:"required"` AttemptsDelay Duration `validate:"required"`
Keystore struct {
Path string `validate:"required"`
Password string `validate:"required"`
} `validate:"required"`
} `validate:"required"` } `validate:"required"`
API struct { API struct {
Coordinator bool Coordinator bool
@ -91,6 +95,9 @@ type Coordinator struct {
// BatchPath if set, specifies the path where batchInfo is stored // BatchPath if set, specifies the path where batchInfo is stored
// in JSON in every step/update of the pipeline // in JSON in every step/update of the pipeline
BatchPath string BatchPath string
// LightScrypt if set, uses light parameters for the ethereum
// keystore encryption algorithm.
LightScrypt bool
} }
} }

+ 40
- 26
coordinator/coordinator.go

@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"math/big" "math/big"
"os"
"strings" "strings"
"sync" "sync"
"time" "time"
@ -111,6 +112,12 @@ func NewCoordinator(cfg Config,
cfg.EthClientAttempts)) cfg.EthClientAttempts))
} }
if cfg.DebugBatchPath != "" {
if err := os.MkdirAll(cfg.DebugBatchPath, 0744); err != nil {
return nil, tracerr.Wrap(err)
}
}
purger := Purger{ purger := Purger{
cfg: cfg.Purger, cfg: cfg.Purger,
lastPurgeBlock: 0, lastPurgeBlock: 0,
@ -147,9 +154,10 @@ func NewCoordinator(cfg Config,
return &c, nil 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, 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 // 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) stats.Eth.LastBlock.Num, "batch", stats.Sync.LastBatch)
batchNum := common.BatchNum(stats.Sync.LastBatch) batchNum := common.BatchNum(stats.Sync.LastBatch)
var err error 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) return tracerr.Wrap(err)
} }
if err := c.pipeline.Start(batchNum, stats.Sync.LastForgeL1TxsNum, 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 { func (c *Coordinator) handleMsg(ctx context.Context, msg interface{}) error {
switch msg := msg.(type) { switch msg := msg.(type) {
case MsgSyncBlock: 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)) return tracerr.Wrap(fmt.Errorf("Coordinator.handleMsgSyncBlock error: %w", err))
} }
case MsgSyncReorg: 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)) return tracerr.Wrap(fmt.Errorf("Coordinator.handleReorg error: %w", err))
} }
case MsgStopPipeline: case MsgStopPipeline:
log.Infow("Coordinator received MsgStopPipeline", "reason", msg.Reason) 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)) return tracerr.Wrap(fmt.Errorf("Coordinator.handleStopPipeline: %w", err))
} }
default: default:
@ -341,7 +343,9 @@ func (c *Coordinator) Start() {
c.wg.Done() c.wg.Done()
return return
case msg := <-c.msgCh: 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) log.Errorw("Coordinator.handleMsg", "err", err)
waitDuration = time.Duration(c.cfg.SyncRetryInterval) waitDuration = time.Duration(c.cfg.SyncRetryInterval)
continue continue
@ -352,7 +356,9 @@ func (c *Coordinator) Start() {
waitDuration = time.Duration(longWaitDuration) waitDuration = time.Duration(longWaitDuration)
continue 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) log.Errorw("Coordinator.syncStats", "err", err)
waitDuration = time.Duration(c.cfg.SyncRetryInterval) waitDuration = time.Duration(c.cfg.SyncRetryInterval)
continue continue
@ -456,7 +462,8 @@ func (t *TxManager) rollupForgeBatch(ctx context.Context, batchInfo *BatchInfo)
return tracerr.Wrap(err) return tracerr.Wrap(err)
} }
log.Errorw("TxManager ethClient.RollupForgeBatch", log.Errorw("TxManager ethClient.RollupForgeBatch",
"attempt", attempt, "err", err, "block", t.lastBlock)
"attempt", attempt, "err", err, "block", t.lastBlock,
"batchNum", batchInfo.BatchNum)
} else { } else {
break break
} }
@ -484,6 +491,9 @@ func (t *TxManager) ethTransactionReceipt(ctx context.Context, batchInfo *BatchI
var err error var err error
for attempt := 0; attempt < t.cfg.EthClientAttempts; attempt++ { for attempt := 0; attempt < t.cfg.EthClientAttempts; attempt++ {
receipt, err = t.ethClient.EthTransactionReceipt(ctx, txHash) receipt, err = t.ethClient.EthTransactionReceipt(ctx, txHash)
if ctx.Err() != nil {
continue
}
if err != nil { if err != nil {
log.Errorw("TxManager ethClient.EthTransactionReceipt", log.Errorw("TxManager ethClient.EthTransactionReceipt",
"attempt", attempt, "err", err) "attempt", attempt, "err", err)
@ -621,6 +631,7 @@ func NewPipeline(ctx context.Context,
purger *Purger, purger *Purger,
txManager *TxManager, txManager *TxManager,
provers []prover.Client, provers []prover.Client,
stats *synchronizer.Stats,
scConsts *synchronizer.SCConsts, scConsts *synchronizer.SCConsts,
) (*Pipeline, error) { ) (*Pipeline, error) {
proversPool := NewProversPool(len(provers)) proversPool := NewProversPool(len(provers))
@ -647,6 +658,7 @@ func NewPipeline(ctx context.Context,
purger: purger, purger: purger,
txManager: txManager, txManager: txManager,
consts: *scConsts, consts: *scConsts,
stats: *stats,
statsCh: make(chan synchronizer.Stats, queueLen), statsCh: make(chan synchronizer.Stats, queueLen),
}, nil }, nil
} }
@ -697,7 +709,7 @@ func (p *Pipeline) Start(batchNum common.BatchNum, lastForgeL1TxsNum int64,
for { for {
select { select {
case <-p.ctx.Done(): case <-p.ctx.Done():
log.Debug("Pipeline forgeBatch loop done")
log.Info("Pipeline forgeBatch loop done")
p.wg.Done() p.wg.Done()
return return
case syncStats := <-p.statsCh: case syncStats := <-p.statsCh:
@ -705,7 +717,7 @@ func (p *Pipeline) Start(batchNum common.BatchNum, lastForgeL1TxsNum int64,
default: default:
batchNum = p.batchNum + 1 batchNum = p.batchNum + 1
batchInfo, err := p.forgeBatch(p.ctx, batchNum, selectionConfig) batchInfo, err := p.forgeBatch(p.ctx, batchNum, selectionConfig)
if common.IsErrDone(err) {
if p.ctx.Err() != nil {
continue continue
} else if err != nil { } else if err != nil {
log.Errorw("forgeBatch", "err", err) 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) // 6. Wait for an available server proof (blocking call)
serverProof, err := p.proversPool.Get(p.ctx) serverProof, err := p.proversPool.Get(p.ctx)
if common.IsErrDone(err) {
if p.ctx.Err() != nil {
continue continue
} else if err != nil { } else if err != nil {
log.Errorw("proversPool.Get", "err", err) log.Errorw("proversPool.Get", "err", err)
continue continue
} }
batchInfo.ServerProof = serverProof 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) log.Errorw("sendServerProof", "err", err)
batchInfo.ServerProof = nil batchInfo.ServerProof = nil
p.proversPool.Add(serverProof) p.proversPool.Add(serverProof)
@ -737,17 +751,17 @@ func (p *Pipeline) Start(batchNum common.BatchNum, lastForgeL1TxsNum int64,
for { for {
select { select {
case <-p.ctx.Done(): case <-p.ctx.Done():
log.Debug("Pipeline waitServerProofSendEth loop done")
log.Info("Pipeline waitServerProofSendEth loop done")
p.wg.Done() p.wg.Done()
return return
case batchInfo := <-batchChSentServerProof: case batchInfo := <-batchChSentServerProof:
err := p.waitServerProof(p.ctx, batchInfo) err := p.waitServerProof(p.ctx, batchInfo)
if common.IsErrDone(err) {
continue
}
// We are done with this serverProof, add it back to the pool // We are done with this serverProof, add it back to the pool
p.proversPool.Add(batchInfo.ServerProof) p.proversPool.Add(batchInfo.ServerProof)
batchInfo.ServerProof = nil batchInfo.ServerProof = nil
if p.ctx.Err() != nil {
continue
}
if err != nil { if err != nil {
log.Errorw("waitServerProof", "err", err) log.Errorw("waitServerProof", "err", err)
continue continue
@ -765,7 +779,7 @@ func (p *Pipeline) Stop(ctx context.Context) {
log.Fatal("Pipeline already stopped") log.Fatal("Pipeline already stopped")
} }
p.started = false p.started = false
log.Debug("Stopping Pipeline...")
log.Info("Stopping Pipeline...")
p.cancel() p.cancel()
p.wg.Wait() p.wg.Wait()
for _, prover := range p.provers { for _, prover := range p.provers {
@ -899,7 +913,7 @@ func (p *Pipeline) waitServerProof(ctx context.Context, batchInfo *BatchInfo) er
} }
batchInfo.Proof = proof batchInfo.Proof = proof
batchInfo.PublicInputs = pubInputs batchInfo.PublicInputs = pubInputs
batchInfo.ForgeBatchArgs = p.prepareForgeBatchArgs(batchInfo)
batchInfo.ForgeBatchArgs = prepareForgeBatchArgs(batchInfo)
batchInfo.TxStatus = TxStatusPending batchInfo.TxStatus = TxStatusPending
p.cfg.debugBatchStore(batchInfo) p.cfg.debugBatchStore(batchInfo)
return nil return nil
@ -921,7 +935,7 @@ func (p *Pipeline) shouldL1L2Batch() bool {
return false return false
} }
func (p *Pipeline) prepareForgeBatchArgs(batchInfo *BatchInfo) *eth.RollupForgeBatchArgs {
func prepareForgeBatchArgs(batchInfo *BatchInfo) *eth.RollupForgeBatchArgs {
proof := batchInfo.Proof proof := batchInfo.Proof
zki := batchInfo.ZKInputs zki := batchInfo.ZKInputs
return &eth.RollupForgeBatchArgs{ return &eth.RollupForgeBatchArgs{

+ 83
- 8
coordinator/coordinator_test.go

@ -10,7 +10,10 @@ import (
"testing" "testing"
"time" "time"
ethKeystore "github.com/ethereum/go-ethereum/accounts/keystore"
ethCommon "github.com/ethereum/go-ethereum/common" 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/batchbuilder"
"github.com/hermeznetwork/hermez-node/common" "github.com/hermeznetwork/hermez-node/common"
dbUtils "github.com/hermeznetwork/hermez-node/db" dbUtils "github.com/hermeznetwork/hermez-node/db"
@ -26,6 +29,7 @@ import (
"github.com/hermeznetwork/hermez-node/txprocessor" "github.com/hermeznetwork/hermez-node/txprocessor"
"github.com/hermeznetwork/hermez-node/txselector" "github.com/hermeznetwork/hermez-node/txselector"
"github.com/hermeznetwork/tracerr" "github.com/hermeznetwork/tracerr"
"github.com/iden3/go-merkletree"
"github.com/iden3/go-merkletree/db/pebble" "github.com/iden3/go-merkletree/db/pebble"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -428,8 +432,9 @@ func TestPipelineShouldL1L2Batch(t *testing.T) {
ctx := context.Background() ctx := context.Background()
ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup) ethClient := test.NewClient(true, &timer, &bidder, ethClientSetup)
modules := newTestModules(t) modules := newTestModules(t)
var stats synchronizer.Stats
coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules) coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
pipeline, err := coord.newPipeline(ctx)
pipeline, err := coord.newPipeline(ctx, &stats)
require.NoError(t, err) require.NoError(t, err)
pipeline.vars = coord.vars pipeline.vars = coord.vars
@ -439,8 +444,6 @@ func TestPipelineShouldL1L2Batch(t *testing.T) {
l1BatchTimeoutPerc := pipeline.cfg.L1BatchTimeoutPerc l1BatchTimeoutPerc := pipeline.cfg.L1BatchTimeoutPerc
l1BatchTimeout := ethClientSetup.RollupVariables.ForgeL1L2BatchTimeout l1BatchTimeout := ethClientSetup.RollupVariables.ForgeL1L2BatchTimeout
var stats synchronizer.Stats
startBlock := int64(100) startBlock := int64(100)
// //
@ -576,11 +579,6 @@ func TestPipeline1(t *testing.T) {
modules := newTestModules(t) modules := newTestModules(t)
coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules) coord := newTestCoordinator(t, forger, ethClient, ethClientSetup, modules)
sync := newTestSynchronizer(t, 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 // preload the synchronier (via the test ethClient) some tokens and
// users with positive balances // users with positive balances
@ -589,6 +587,9 @@ func TestPipeline1(t *testing.T) {
batchNum := common.BatchNum(syncStats.Sync.LastBatch) batchNum := common.BatchNum(syncStats.Sync.LastBatch)
syncSCVars := sync.SCVars() syncSCVars := sync.SCVars()
pipeline, err := coord.newPipeline(ctx, syncStats)
require.NoError(t, err)
// Insert some l2txs in the Pool // Insert some l2txs in the Pool
setPool := ` setPool := `
Type: PoolL2 Type: PoolL2
@ -713,6 +714,80 @@ func TestCoordinatorStress(t *testing.T) {
coord.Stop() 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, &eth.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 Reorg
// TODO: Test Pipeline // TODO: Test Pipeline
// TODO: Test TxMonitor // TODO: Test TxMonitor

+ 4
- 0
db/statedb/statedb_test.go

@ -112,6 +112,10 @@ func TestNewStateDBIntermediateState(t *testing.T) {
sdb, err = NewStateDB(dir, 128, TypeTxSelector, 0) sdb, err = NewStateDB(dir, 128, TypeTxSelector, 0)
assert.NoError(t, err) 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) v, err = sdb.db.DB().Get(k0)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, v0, v) assert.Equal(t, v0, v)

+ 4
- 1
eth/client.go

@ -65,7 +65,10 @@ type ClientConfig struct {
// NewClient creates a new Client to interact with Ethereum and the Hermez smart contracts. // 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) { 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) auctionClient, err := NewAuctionClient(ethereumClient, cfg.Auction.Address, cfg.Auction.TokenHEZ)
if err != nil { if err != nil {
return nil, tracerr.Wrap(err) return nil, tracerr.Wrap(err)

+ 10
- 4
eth/ethereum.go

@ -73,6 +73,7 @@ type EthereumConfig struct {
// EthereumClient is an ethereum client to call Smart Contract methods and check blockchain information. // EthereumClient is an ethereum client to call Smart Contract methods and check blockchain information.
type EthereumClient struct { type EthereumClient struct {
client *ethclient.Client client *ethclient.Client
chainID *big.Int
account *accounts.Account account *accounts.Account
ks *ethKeystore.KeyStore ks *ethKeystore.KeyStore
ReceiptTimeout time.Duration ReceiptTimeout time.Duration
@ -82,7 +83,7 @@ type EthereumClient struct {
// NewEthereumClient creates a EthereumClient instance. The account is not mandatory (it can // NewEthereumClient creates a EthereumClient instance. The account is not mandatory (it can
// be nil). If the account is nil, CallAuth will fail with ErrAccountNil. // 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 { if config == nil {
config = &EthereumConfig{ config = &EthereumConfig{
CallGasLimit: defaultCallGasLimit, CallGasLimit: defaultCallGasLimit,
@ -92,7 +93,7 @@ func NewEthereumClient(client *ethclient.Client, account *accounts.Account, ks *
IntervalReceiptLoop: defaultIntervalReceiptLoop, IntervalReceiptLoop: defaultIntervalReceiptLoop,
} }
} }
return &EthereumClient{
c := &EthereumClient{
client: client, client: client,
account: account, account: account,
ks: ks, ks: ks,
@ -100,6 +101,12 @@ func NewEthereumClient(client *ethclient.Client, account *accounts.Account, ks *
config: config, config: config,
opts: newCallOpts(), 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 // EthChainID returns the ChainID of the ethereum network
@ -147,8 +154,7 @@ func (c *EthereumClient) CallAuth(gasLimit uint64,
gasPrice.Add(gasPrice, inc) gasPrice.Add(gasPrice, inc)
log.Debugw("Transaction metadata", "gasPrice", gasPrice) 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 { if err != nil {
return nil, tracerr.Wrap(err) return nil, tracerr.Wrap(err)
} }

+ 2
- 1
eth/ethereum_test.go

@ -11,7 +11,8 @@ import (
func TestEthERC20(t *testing.T) { func TestEthERC20(t *testing.T) {
ethClient, err := ethclient.Dial(ethClientDialURL) ethClient, err := ethclient.Dial(ethClientDialURL)
require.Nil(t, err) 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) consts, err := client.EthERC20Consts(tokenHEZAddressConst)
require.Nil(t, err) require.Nil(t, err)

+ 20
- 5
eth/main_test.go

@ -164,7 +164,10 @@ func TestMain(m *testing.M) {
} }
// Controllable Governance Address // 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) auctionClient, err = NewAuctionClient(ethereumClientGov, auctionAddressConst, tokenHEZ)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@ -186,10 +189,22 @@ func TestMain(m *testing.M) {
log.Fatal(err) 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() exitVal = m.Run()
} }

+ 28
- 1
node/node.go

@ -7,6 +7,8 @@ import (
"sync" "sync"
"time" "time"
"github.com/ethereum/go-ethereum/accounts"
ethKeystore "github.com/ethereum/go-ethereum/accounts/keystore"
ethCommon "github.com/ethereum/go-ethereum/common" ethCommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/gin-contrib/cors" "github.com/gin-contrib/cors"
@ -87,6 +89,8 @@ func NewNode(mode Mode, cfg *config.Node) (*Node, error) {
return nil, tracerr.Wrap(err) return nil, tracerr.Wrap(err)
} }
var ethCfg eth.EthereumConfig var ethCfg eth.EthereumConfig
var account *accounts.Account
var keyStore *ethKeystore.KeyStore
if mode == ModeCoordinator { if mode == ModeCoordinator {
ethCfg = eth.EthereumConfig{ ethCfg = eth.EthereumConfig{
CallGasLimit: cfg.Coordinator.EthClient.CallGasLimit, CallGasLimit: cfg.Coordinator.EthClient.CallGasLimit,
@ -95,8 +99,31 @@ func NewNode(mode Mode, cfg *config.Node) (*Node, error) {
ReceiptTimeout: cfg.Coordinator.EthClient.ReceiptTimeout.Duration, ReceiptTimeout: cfg.Coordinator.EthClient.ReceiptTimeout.Duration,
IntervalReceiptLoop: cfg.Coordinator.EthClient.ReceiptLoopInterval.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, &eth.ClientConfig{
client, err := eth.NewClient(ethClient, account, keyStore, &eth.ClientConfig{
Ethereum: ethCfg, Ethereum: ethCfg,
Rollup: eth.RollupConfig{ Rollup: eth.RollupConfig{
Address: cfg.SmartContracts.Rollup, Address: cfg.SmartContracts.Rollup,

Loading…
Cancel
Save