mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-07 11:26:44 +01:00
Merge pull request #264 from hermeznetwork/feature/integration11
Add DebugAPI to Node, fix StateDB
This commit is contained in:
@@ -1,3 +1,6 @@
|
|||||||
|
[Debug]
|
||||||
|
APIAddress = "localhost:12345"
|
||||||
|
|
||||||
[StateDB]
|
[StateDB]
|
||||||
Path = "/tmp/iden3-test/hermez/statedb"
|
Path = "/tmp/iden3-test/hermez/statedb"
|
||||||
|
|
||||||
|
|||||||
@@ -84,6 +84,9 @@ type Node struct {
|
|||||||
ReceiptTimeout Duration `validate:"required"`
|
ReceiptTimeout Duration `validate:"required"`
|
||||||
IntervalReceiptLoop Duration `validate:"required"`
|
IntervalReceiptLoop Duration `validate:"required"`
|
||||||
} `validate:"required"`
|
} `validate:"required"`
|
||||||
|
Debug struct {
|
||||||
|
APIAddress string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load loads a generic config.
|
// Load loads a generic config.
|
||||||
|
|||||||
@@ -48,8 +48,6 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// PathStateDB defines the subpath of the StateDB
|
|
||||||
PathStateDB = "/statedb"
|
|
||||||
// PathBatchNum defines the subpath of the Batch Checkpoint in the
|
// PathBatchNum defines the subpath of the Batch Checkpoint in the
|
||||||
// subpath of the StateDB
|
// subpath of the StateDB
|
||||||
PathBatchNum = "/BatchNum"
|
PathBatchNum = "/BatchNum"
|
||||||
@@ -88,7 +86,7 @@ type StateDB struct {
|
|||||||
func NewStateDB(path string, typ TypeStateDB, nLevels int) (*StateDB, error) {
|
func NewStateDB(path string, typ TypeStateDB, nLevels int) (*StateDB, error) {
|
||||||
var sto *pebble.PebbleStorage
|
var sto *pebble.PebbleStorage
|
||||||
var err error
|
var err error
|
||||||
sto, err = pebble.NewPebbleStorage(path+PathStateDB+PathCurrent, false)
|
sto, err = pebble.NewPebbleStorage(path+PathCurrent, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -105,7 +103,7 @@ func NewStateDB(path string, typ TypeStateDB, nLevels int) (*StateDB, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sdb := &StateDB{
|
sdb := &StateDB{
|
||||||
path: path + PathStateDB,
|
path: path,
|
||||||
db: sto,
|
db: sto,
|
||||||
mt: mt,
|
mt: mt,
|
||||||
typ: typ,
|
typ: typ,
|
||||||
@@ -163,6 +161,7 @@ func (s *StateDB) setCurrentBatch() error {
|
|||||||
func (s *StateDB) MakeCheckpoint() error {
|
func (s *StateDB) MakeCheckpoint() error {
|
||||||
// advance currentBatch
|
// advance currentBatch
|
||||||
s.currentBatch++
|
s.currentBatch++
|
||||||
|
log.Debugw("Making StateDB checkpoint", "batch", s.currentBatch, "type", s.typ)
|
||||||
|
|
||||||
checkpointPath := s.path + PathBatchNum + strconv.Itoa(int(s.currentBatch))
|
checkpointPath := s.path + PathBatchNum + strconv.Itoa(int(s.currentBatch))
|
||||||
|
|
||||||
|
|||||||
@@ -49,8 +49,13 @@ type ProcessTxOutput struct {
|
|||||||
// the HistoryDB, and adds Nonce & TokenID to the L2Txs.
|
// the HistoryDB, and adds Nonce & TokenID to the L2Txs.
|
||||||
// And if TypeSynchronizer returns an array of common.Account with all the
|
// And if TypeSynchronizer returns an array of common.Account with all the
|
||||||
// created accounts.
|
// created accounts.
|
||||||
func (s *StateDB) ProcessTxs(coordIdxs []common.Idx, l1usertxs, l1coordinatortxs []common.L1Tx, l2txs []common.PoolL2Tx) (*ProcessTxOutput, error) {
|
func (s *StateDB) ProcessTxs(coordIdxs []common.Idx, l1usertxs, l1coordinatortxs []common.L1Tx, l2txs []common.PoolL2Tx) (ptOut *ProcessTxOutput, err error) {
|
||||||
var err error
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
err = s.MakeCheckpoint()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
var exitTree *merkletree.MerkleTree
|
var exitTree *merkletree.MerkleTree
|
||||||
var createdAccounts []common.Account
|
var createdAccounts []common.Account
|
||||||
|
|
||||||
@@ -829,7 +834,7 @@ func (s *StateDB) getIdx() (common.Idx, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return common.IdxFromBytes(idxBytes[:4])
|
return common.IdxFromBytes(idxBytes[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// setIdx stores Idx in the localStateDB
|
// setIdx stores Idx in the localStateDB
|
||||||
|
|||||||
46
node/node.go
46
node/node.go
@@ -2,6 +2,7 @@ package node
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/ethclient"
|
"github.com/ethereum/go-ethereum/ethclient"
|
||||||
@@ -16,6 +17,7 @@ import (
|
|||||||
"github.com/hermeznetwork/hermez-node/eth"
|
"github.com/hermeznetwork/hermez-node/eth"
|
||||||
"github.com/hermeznetwork/hermez-node/log"
|
"github.com/hermeznetwork/hermez-node/log"
|
||||||
"github.com/hermeznetwork/hermez-node/synchronizer"
|
"github.com/hermeznetwork/hermez-node/synchronizer"
|
||||||
|
"github.com/hermeznetwork/hermez-node/test/debugapi"
|
||||||
"github.com/hermeznetwork/hermez-node/txselector"
|
"github.com/hermeznetwork/hermez-node/txselector"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
)
|
)
|
||||||
@@ -37,6 +39,7 @@ const (
|
|||||||
|
|
||||||
// Node is the Hermez Node
|
// Node is the Hermez Node
|
||||||
type Node struct {
|
type Node struct {
|
||||||
|
debugAPI *debugapi.DebugAPI
|
||||||
// Coordinator
|
// Coordinator
|
||||||
coord *coordinator.Coordinator
|
coord *coordinator.Coordinator
|
||||||
coordCfg *config.Coordinator
|
coordCfg *config.Coordinator
|
||||||
@@ -48,14 +51,14 @@ type Node struct {
|
|||||||
stoppedForgeCallConfirm chan bool
|
stoppedForgeCallConfirm chan bool
|
||||||
|
|
||||||
// Synchronizer
|
// Synchronizer
|
||||||
sync *synchronizer.Synchronizer
|
sync *synchronizer.Synchronizer
|
||||||
stoppedSync chan bool
|
|
||||||
|
|
||||||
// General
|
// General
|
||||||
cfg *config.Node
|
cfg *config.Node
|
||||||
mode Mode
|
mode Mode
|
||||||
sqlConn *sqlx.DB
|
sqlConn *sqlx.DB
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
wg sync.WaitGroup
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,8 +158,14 @@ func NewNode(mode Mode, cfg *config.Node, coordCfg *config.Coordinator) (*Node,
|
|||||||
client,
|
client,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
var debugAPI *debugapi.DebugAPI
|
||||||
|
println("apiaddr", cfg.Debug.APIAddress)
|
||||||
|
if cfg.Debug.APIAddress != "" {
|
||||||
|
debugAPI = debugapi.NewDebugAPI(cfg.Debug.APIAddress, stateDB)
|
||||||
|
}
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
return &Node{
|
return &Node{
|
||||||
|
debugAPI: debugAPI,
|
||||||
coord: coord,
|
coord: coord,
|
||||||
coordCfg: coordCfg,
|
coordCfg: coordCfg,
|
||||||
sync: sync,
|
sync: sync,
|
||||||
@@ -172,6 +181,9 @@ func NewNode(mode Mode, cfg *config.Node, coordCfg *config.Coordinator) (*Node,
|
|||||||
func (n *Node) StartCoordinator() {
|
func (n *Node) StartCoordinator() {
|
||||||
log.Info("Starting Coordinator...")
|
log.Info("Starting Coordinator...")
|
||||||
|
|
||||||
|
// TODO: Replace stopXXX by context
|
||||||
|
// TODO: Replace stoppedXXX by waitgroup
|
||||||
|
|
||||||
n.stopForge = make(chan bool)
|
n.stopForge = make(chan bool)
|
||||||
n.stopGetProofCallForge = make(chan bool)
|
n.stopGetProofCallForge = make(chan bool)
|
||||||
n.stopForgeCallConfirm = make(chan bool)
|
n.stopForgeCallConfirm = make(chan bool)
|
||||||
@@ -249,18 +261,18 @@ func (n *Node) StopCoordinator() {
|
|||||||
// StartSynchronizer starts the synchronizer
|
// StartSynchronizer starts the synchronizer
|
||||||
func (n *Node) StartSynchronizer() {
|
func (n *Node) StartSynchronizer() {
|
||||||
log.Info("Starting Synchronizer...")
|
log.Info("Starting Synchronizer...")
|
||||||
// stopped channel is size 1 so that the defer doesn't block
|
n.wg.Add(1)
|
||||||
n.stoppedSync = make(chan bool, 1)
|
|
||||||
go func() {
|
go func() {
|
||||||
defer func() {
|
defer func() {
|
||||||
n.stoppedSync <- true
|
log.Info("Synchronizer routine stopped")
|
||||||
|
n.wg.Done()
|
||||||
}()
|
}()
|
||||||
var lastBlock *common.Block
|
var lastBlock *common.Block
|
||||||
d := time.Duration(0)
|
d := time.Duration(0)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-n.ctx.Done():
|
case <-n.ctx.Done():
|
||||||
log.Info("Synchronizer stopped")
|
log.Info("Synchronizer done")
|
||||||
return
|
return
|
||||||
case <-time.After(d):
|
case <-time.After(d):
|
||||||
if blockData, discarded, err := n.sync.Sync2(n.ctx, lastBlock); err != nil {
|
if blockData, discarded, err := n.sync.Sync2(n.ctx, lastBlock); err != nil {
|
||||||
@@ -283,15 +295,27 @@ func (n *Node) StartSynchronizer() {
|
|||||||
// TODO: Run price updater. This is required by the API and the TxSelector
|
// TODO: Run price updater. This is required by the API and the TxSelector
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaitStopSynchronizer waits for the synchronizer to stop
|
// StartDebugAPI starts the DebugAPI
|
||||||
func (n *Node) WaitStopSynchronizer() {
|
func (n *Node) StartDebugAPI() {
|
||||||
log.Info("Waiting for Synchronizer to stop...")
|
log.Info("Starting DebugAPI...")
|
||||||
<-n.stoppedSync
|
n.wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
log.Info("DebugAPI routine stopped")
|
||||||
|
n.wg.Done()
|
||||||
|
}()
|
||||||
|
if err := n.debugAPI.Run(n.ctx); err != nil {
|
||||||
|
log.Fatalw("DebugAPI.Run", "err", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the node
|
// Start the node
|
||||||
func (n *Node) Start() {
|
func (n *Node) Start() {
|
||||||
log.Infow("Starting node...", "mode", n.mode)
|
log.Infow("Starting node...", "mode", n.mode)
|
||||||
|
if n.debugAPI != nil {
|
||||||
|
n.StartDebugAPI()
|
||||||
|
}
|
||||||
if n.mode == ModeCoordinator {
|
if n.mode == ModeCoordinator {
|
||||||
n.StartCoordinator()
|
n.StartCoordinator()
|
||||||
}
|
}
|
||||||
@@ -305,5 +329,5 @@ func (n *Node) Stop() {
|
|||||||
if n.mode == ModeCoordinator {
|
if n.mode == ModeCoordinator {
|
||||||
n.StopCoordinator()
|
n.StopCoordinator()
|
||||||
}
|
}
|
||||||
n.WaitStopSynchronizer()
|
n.wg.Wait()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,6 +92,9 @@ func (a *DebugAPI) Run(ctx context.Context) error {
|
|||||||
|
|
||||||
debugAPI.GET("sdb/batchnum", a.handleCurrentBatch)
|
debugAPI.GET("sdb/batchnum", a.handleCurrentBatch)
|
||||||
debugAPI.GET("sdb/mtroot", a.handleMTRoot)
|
debugAPI.GET("sdb/mtroot", a.handleMTRoot)
|
||||||
|
// Accounts returned by these endpoints will always have BatchNum = 0,
|
||||||
|
// because the stateDB doesn't store the BatchNum in which an account
|
||||||
|
// is created.
|
||||||
debugAPI.GET("sdb/accounts", a.handleAccounts)
|
debugAPI.GET("sdb/accounts", a.handleAccounts)
|
||||||
debugAPI.GET("sdb/accounts/:Idx", a.handleAccount)
|
debugAPI.GET("sdb/accounts/:Idx", a.handleAccount)
|
||||||
|
|
||||||
@@ -104,7 +107,7 @@ func (a *DebugAPI) Run(ctx context.Context) error {
|
|||||||
MaxHeaderBytes: 1 << 20, //nolint:gomnd
|
MaxHeaderBytes: 1 << 20, //nolint:gomnd
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
log.Infof("Debug API is ready at %v", a.addr)
|
log.Infof("DebugAPI is ready at %v", a.addr)
|
||||||
if err := debugAPIServer.ListenAndServe(); err != nil &&
|
if err := debugAPIServer.ListenAndServe(); err != nil &&
|
||||||
err != http.ErrServerClosed {
|
err != http.ErrServerClosed {
|
||||||
log.Fatalf("Listen: %s\n", err)
|
log.Fatalf("Listen: %s\n", err)
|
||||||
@@ -112,10 +115,10 @@ func (a *DebugAPI) Run(ctx context.Context) error {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
log.Info("Stopping Debug API...")
|
log.Info("Stopping DebugAPI...")
|
||||||
if err := debugAPIServer.Shutdown(context.Background()); err != nil {
|
if err := debugAPIServer.Shutdown(context.Background()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Info("Debug API stopped")
|
log.Info("DebugAPI done")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user