arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/coordinator/coordinator_test.go
coordinator/coordinator_test.goRaw
  1package coordinator
  2
  3import (
  4	"io/ioutil"
  5	"math/big"
  6	"os"
  7	"testing"
  8	"time"
  9
 10	ethCommon "github.com/ethereum/go-ethereum/common"
 11	"github.com/hermeznetwork/hermez-node/batchbuilder"
 12	dbUtils "github.com/hermeznetwork/hermez-node/db"
 13	"github.com/hermeznetwork/hermez-node/db/historydb"
 14	"github.com/hermeznetwork/hermez-node/db/l2db"
 15	"github.com/hermeznetwork/hermez-node/db/statedb"
 16	"github.com/hermeznetwork/hermez-node/log"
 17	"github.com/hermeznetwork/hermez-node/test"
 18	"github.com/hermeznetwork/hermez-node/txselector"
 19	"github.com/stretchr/testify/assert"
 20	"github.com/stretchr/testify/require"
 21)
 22
 23func newTestModules(t *testing.T) (*txselector.TxSelector, *batchbuilder.BatchBuilder) { // FUTURE once Synchronizer is ready, should return it also
 24	nLevels := 32
 25
 26	synchDB, err := ioutil.TempDir("", "tmpSynchDB")
 27	require.Nil(t, err)
 28	sdb, err := statedb.NewStateDB(synchDB, true, nLevels)
 29	assert.Nil(t, err)
 30
 31	pass := os.Getenv("POSTGRES_PASS")
 32	db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez")
 33	require.Nil(t, err)
 34	l2DB := l2db.NewL2DB(db, 10, 100, 24*time.Hour)
 35
 36	txselDir, err := ioutil.TempDir("", "tmpTxSelDB")
 37	require.Nil(t, err)
 38	txsel, err := txselector.NewTxSelector(txselDir, sdb, l2DB, 10, 10, 10)
 39	assert.Nil(t, err)
 40
 41	bbDir, err := ioutil.TempDir("", "tmpBatchBuilderDB")
 42	require.Nil(t, err)
 43	bb, err := batchbuilder.NewBatchBuilder(bbDir, sdb, nil, 0, uint64(nLevels))
 44	assert.Nil(t, err)
 45
 46	// l1Txs, coordinatorL1Txs, poolL2Txs := test.GenerateTestTxsFromSet(t, test.SetTest0)
 47
 48	return txsel, bb
 49}
 50
 51// CoordNode is an example of a Node that handles the goroutines for the coordinator
 52type CoordNode struct {
 53	c                     *Coordinator
 54	stopForge             chan bool
 55	stopGetProofCallForge chan bool
 56	stopForgeCallConfirm  chan bool
 57}
 58
 59func NewCoordNode(c *Coordinator) *CoordNode {
 60	return &CoordNode{
 61		c: c,
 62	}
 63}
 64
 65func (cn *CoordNode) Start() {
 66	log.Debugw("Starting CoordNode...")
 67	cn.stopForge = make(chan bool)
 68	cn.stopGetProofCallForge = make(chan bool)
 69	cn.stopForgeCallConfirm = make(chan bool)
 70	queueSize := 8
 71	batchCh0 := make(chan *BatchInfo, queueSize)
 72	batchCh1 := make(chan *BatchInfo, queueSize)
 73
 74	go func() {
 75		for {
 76			select {
 77			case <-cn.stopForge:
 78				return
 79			default:
 80				if forge, err := cn.c.ForgeLoopFn(batchCh0, cn.stopForge); err == ErrStop {
 81					return
 82				} else if err != nil {
 83					log.Errorw("CoordNode ForgeLoopFn", "error", err)
 84					time.Sleep(200 * time.Millisecond) // Avoid overflowing log with errors
 85				} else if !forge {
 86					time.Sleep(200 * time.Millisecond)
 87				}
 88			}
 89		}
 90	}()
 91	go func() {
 92		for {
 93			select {
 94			case <-cn.stopGetProofCallForge:
 95				return
 96			default:
 97				if err := cn.c.GetProofCallForgeLoopFn(
 98					batchCh0, batchCh1, cn.stopGetProofCallForge); err == ErrStop {
 99					return
100				} else if err != nil {
101					log.Errorw("CoordNode GetProofCallForgeLoopFn", "error", err)
102				}
103			}
104		}
105	}()
106	go func() {
107		for {
108			select {
109			case <-cn.stopForgeCallConfirm:
110				return
111			default:
112				if err := cn.c.ForgeCallConfirmLoopFn(
113					batchCh1, cn.stopForgeCallConfirm); err == ErrStop {
114					return
115				} else if err != nil {
116					log.Errorw("CoordNode ForgeCallConfirmLoopFn", "error", err)
117				}
118			}
119		}
120	}()
121}
122
123func (cn *CoordNode) Stop() {
124	log.Debugw("Stopping CoordNode...")
125	cn.stopForge <- true
126	cn.stopGetProofCallForge <- true
127	cn.stopForgeCallConfirm <- true
128}
129
130type timer struct {
131	time int64
132}
133
134func (t *timer) Time() int64 {
135	currentTime := t.time
136	t.time++
137	return currentTime
138}
139
140func waitForSlot(t *testing.T, c *test.Client, slot int64) {
141	for {
142		blockNum, err := c.EthCurrentBlock()
143		require.Nil(t, err)
144		nextBlockSlot, err := c.AuctionGetSlotNumber(blockNum + 1)
145		require.Nil(t, err)
146		if nextBlockSlot == slot {
147			break
148		}
149		c.CtlMineBlock()
150	}
151}
152
153func TestCoordinator(t *testing.T) {
154	txsel, bb := newTestModules(t)
155
156	conf := Config{}
157	hdb := &historydb.HistoryDB{}
158	serverProofs := []ServerProofInterface{&ServerProofMock{}, &ServerProofMock{}}
159
160	var timer timer
161	ethClientSetup := test.NewClientSetupExample()
162	addr := ethCommon.HexToAddress("0xc344E203a046Da13b0B4467EB7B3629D0C99F6E6")
163	ethClient := test.NewClient(true, &timer, &addr, ethClientSetup)
164
165	// Bid for slot 2 and 4
166	_, err := ethClient.AuctionRegisterCoordinator(addr, "https://foo.bar")
167	require.Nil(t, err)
168	_, err = ethClient.AuctionBid(2, big.NewInt(9999), addr)
169	require.Nil(t, err)
170	_, err = ethClient.AuctionBid(4, big.NewInt(9999), addr)
171	require.Nil(t, err)
172
173	c := NewCoordinator(conf, hdb, txsel, bb, serverProofs, ethClient)
174	cn := NewCoordNode(c)
175	cn.Start()
176	time.Sleep(1 * time.Second)
177
178	// simulate forgeSequence time
179	waitForSlot(t, ethClient, 2)
180	log.Info("simulate entering in forge time")
181	time.Sleep(1 * time.Second)
182
183	// simulate going out from forgeSequence
184	waitForSlot(t, ethClient, 3)
185	log.Info("simulate going out from forge time")
186	time.Sleep(1 * time.Second)
187
188	// simulate entering forgeSequence time again
189	waitForSlot(t, ethClient, 4)
190	log.Info("simulate entering in forge time again")
191	time.Sleep(2 * time.Second)
192
193	// simulate stopping forgerLoop by channel
194	log.Info("simulate stopping forgerLoop by closing coordinator stopch")
195	cn.Stop()
196	time.Sleep(1 * time.Second)
197}