diff --git a/db/statedb/txprocessors.go b/db/statedb/txprocessors.go index 30f4256..e7f38e6 100644 --- a/db/statedb/txprocessors.go +++ b/db/statedb/txprocessors.go @@ -30,16 +30,15 @@ func (s *StateDB) ProcessTxs(cmpExitTree bool, l1usertxs, l1coordinatortxs []*co var err error var exitTree *merkletree.MerkleTree exits := make(map[common.Idx]common.Account) - if cmpExitTree { - // TBD if ExitTree is only in memory or stored in disk, for the moment - // only needed in memory - exitTree, err = merkletree.NewMerkleTree(memory.NewMemoryStorage(), s.mt.MaxLevels()) - if err != nil { - return nil, nil, err - } + + // TBD if ExitTree is only in memory or stored in disk, for the moment + // only needed in memory + exitTree, err = merkletree.NewMerkleTree(memory.NewMemoryStorage(), s.mt.MaxLevels()) + if err != nil { + return nil, nil, err } - for _, tx := range l1usertxs { + for _, tx := range l1coordinatortxs { exitIdx, exitAccount, err := s.processL1Tx(exitTree, tx) if err != nil { return nil, nil, err @@ -48,7 +47,7 @@ func (s *StateDB) ProcessTxs(cmpExitTree bool, l1usertxs, l1coordinatortxs []*co exits[*exitIdx] = *exitAccount } } - for _, tx := range l1coordinatortxs { + for _, tx := range l1usertxs { exitIdx, exitAccount, err := s.processL1Tx(exitTree, tx) if err != nil { return nil, nil, err @@ -108,29 +107,6 @@ func (s *StateDB) ProcessTxs(cmpExitTree bool, l1usertxs, l1coordinatortxs []*co return nil, exitInfos, nil } -// processL2Tx process the given L2Tx applying the needed updates to -// the StateDB depending on the transaction Type. -func (s *StateDB) processL2Tx(exitTree *merkletree.MerkleTree, tx *common.L2Tx) (*common.Idx, *common.Account, error) { - switch tx.Type { - case common.TxTypeTransfer: - // go to the MT account of sender and receiver, and update - // balance & nonce - err := s.applyTransfer(tx.Tx()) - if err != nil { - return nil, nil, err - } - case common.TxTypeExit: - // execute exit flow - exitAccount, err := s.applyExit(exitTree, tx.Tx()) - if err != nil { - return nil, nil, err - } - return &tx.FromIdx, exitAccount, nil - default: - } - return nil, nil, nil -} - // processL1Tx process the given L1Tx applying the needed updates to the // StateDB depending on the transaction Type. func (s *StateDB) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx) (*common.Idx, *common.Account, error) { @@ -185,6 +161,29 @@ func (s *StateDB) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx) return nil, nil, nil } +// processL2Tx process the given L2Tx applying the needed updates to +// the StateDB depending on the transaction Type. +func (s *StateDB) processL2Tx(exitTree *merkletree.MerkleTree, tx *common.L2Tx) (*common.Idx, *common.Account, error) { + switch tx.Type { + case common.TxTypeTransfer: + // go to the MT account of sender and receiver, and update + // balance & nonce + err := s.applyTransfer(tx.Tx()) + if err != nil { + return nil, nil, err + } + case common.TxTypeExit: + // execute exit flow + exitAccount, err := s.applyExit(exitTree, tx.Tx()) + if err != nil { + return nil, nil, err + } + return &tx.FromIdx, exitAccount, nil + default: + } + return nil, nil, nil +} + // applyCreateAccount creates a new account in the account of the depositer, it // stores the deposit value func (s *StateDB) applyCreateAccount(tx *common.L1Tx) error { diff --git a/db/statedb/txprocessors_test.go b/db/statedb/txprocessors_test.go new file mode 100644 index 0000000..5a9dd06 --- /dev/null +++ b/db/statedb/txprocessors_test.go @@ -0,0 +1,93 @@ +package statedb + +import ( + "io/ioutil" + "strings" + "testing" + + "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/test" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestProcessTxs(t *testing.T) { + dir, err := ioutil.TempDir("", "tmpdb") + require.Nil(t, err) + + sdb, err := NewStateDB(dir, true, 32) + assert.Nil(t, err) + + // generate test transactions from test.SetTest0 code + parser := test.NewParser(strings.NewReader(test.SetTest0)) + instructions, err := parser.Parse() + assert.Nil(t, err) + + l1Txs, coordinatorL1Txs, poolL2Txs := test.GenerateTestTxs(t, instructions) + assert.Equal(t, 29, len(l1Txs[0])) + assert.Equal(t, 0, len(coordinatorL1Txs[0])) + assert.Equal(t, 21, len(poolL2Txs[0])) + + // iterate for each batch + for i := 0; i < len(l1Txs); i++ { + l2Txs := common.PoolL2TxsToL2Txs(poolL2Txs[i]) + + _, _, err := sdb.ProcessTxs(true, l1Txs[i], coordinatorL1Txs[i], l2Txs) + require.Nil(t, err) + } + + acc, err := sdb.GetAccount(common.Idx(1)) + assert.Nil(t, err) + assert.Equal(t, "23", acc.Balance.String()) +} + +func TestProcessTxsBatchByBatch(t *testing.T) { + dir, err := ioutil.TempDir("", "tmpdb") + require.Nil(t, err) + + sdb, err := NewStateDB(dir, true, 32) + assert.Nil(t, err) + + // generate test transactions from test.SetTest0 code + parser := test.NewParser(strings.NewReader(test.SetTest0)) + instructions, err := parser.Parse() + assert.Nil(t, err) + + l1Txs, coordinatorL1Txs, poolL2Txs := test.GenerateTestTxs(t, instructions) + assert.Equal(t, 29, len(l1Txs[0])) + assert.Equal(t, 0, len(coordinatorL1Txs[0])) + assert.Equal(t, 21, len(poolL2Txs[0])) + assert.Equal(t, 5, len(l1Txs[1])) + assert.Equal(t, 1, len(coordinatorL1Txs[1])) + assert.Equal(t, 55, len(poolL2Txs[1])) + assert.Equal(t, 10, len(l1Txs[2])) + assert.Equal(t, 0, len(coordinatorL1Txs[2])) + assert.Equal(t, 7, len(poolL2Txs[2])) + + // use first batch + l2txs := common.PoolL2TxsToL2Txs(poolL2Txs[0]) + _, exitInfos, err := sdb.ProcessTxs(true, l1Txs[0], coordinatorL1Txs[0], l2txs) + require.Nil(t, err) + assert.Equal(t, 0, len(exitInfos)) + acc, err := sdb.GetAccount(common.Idx(1)) + assert.Nil(t, err) + assert.Equal(t, "28", acc.Balance.String()) + + // use second batch + l2txs = common.PoolL2TxsToL2Txs(poolL2Txs[1]) + _, exitInfos, err = sdb.ProcessTxs(true, l1Txs[1], coordinatorL1Txs[1], l2txs) + require.Nil(t, err) + assert.Equal(t, 5, len(exitInfos)) + acc, err = sdb.GetAccount(common.Idx(1)) + assert.Nil(t, err) + assert.Equal(t, "48", acc.Balance.String()) + + // use third batch + l2txs = common.PoolL2TxsToL2Txs(poolL2Txs[2]) + _, exitInfos, err = sdb.ProcessTxs(true, l1Txs[2], coordinatorL1Txs[2], l2txs) + require.Nil(t, err) + assert.Equal(t, 1, len(exitInfos)) + acc, err = sdb.GetAccount(common.Idx(1)) + assert.Nil(t, err) + assert.Equal(t, "23", acc.Balance.String()) +} diff --git a/test/sets.go b/test/sets.go index 0e6d21a..8521c2d 100644 --- a/test/sets.go +++ b/test/sets.go @@ -164,6 +164,3 @@ var SetTest0 = ` I-H (1): 5 1 A (1) E: 5 ` - -// cases to add: -// - L2 tx from B to A, when B still does not have tokens, which will receive from C