From a6006ebde758ba6b2deb39113b880c10149cd878 Mon Sep 17 00:00:00 2001 From: arnaucube Date: Thu, 15 Oct 2020 12:26:49 +0200 Subject: [PATCH] Add transakcio Token Register instructions parser --- db/statedb/txprocessors.go | 5 +-- db/statedb/txprocessors_test.go | 3 +- test/transakcio/lang.go | 60 ++++++++++++++++++------- test/transakcio/lang_test.go | 45 +++++++++++++------ test/transakcio/sets.go | 3 ++ test/transakcio/sets_test.go | 6 ++- test/transakcio/txs.go | 79 ++++++++++++++++++++++----------- test/transakcio/txs_test.go | 57 ++++++++++++++++++++++-- 8 files changed, 192 insertions(+), 66 deletions(-) diff --git a/db/statedb/txprocessors.go b/db/statedb/txprocessors.go index 28e06e8..d747c7a 100644 --- a/db/statedb/txprocessors.go +++ b/db/statedb/txprocessors.go @@ -366,10 +366,7 @@ func (s *StateDB) processL2Tx(exitTree *merkletree.MerkleTree, tx *common.PoolL2 return nil, nil, false, err } tx.Nonce = acc.Nonce - // TokenID is also not set in the L2Txs from the blockchain - // that the Synchronizer works with, but does not need to be - // defined because is not used later for the L2Txs processing - // (Transfer & Exit) + tx.TokenID = acc.TokenID } switch tx.Type { diff --git a/db/statedb/txprocessors_test.go b/db/statedb/txprocessors_test.go index 6e44571..13c2d1f 100644 --- a/db/statedb/txprocessors_test.go +++ b/db/statedb/txprocessors_test.go @@ -22,7 +22,8 @@ func TestProcessTxsSynchronizer(t *testing.T) { // generate test transactions from test.SetTest0 code tc := transakcio.NewTestContext() - blocks := tc.GenerateBlocks(transakcio.SetBlockchain0) + blocks, err := tc.GenerateBlocks(transakcio.SetBlockchain0) + require.Nil(t, err) assert.Equal(t, 29, len(blocks[0].Batches[0].L1UserTxs)) assert.Equal(t, 0, len(blocks[0].Batches[0].L1CoordinatorTxs)) diff --git a/test/transakcio/lang.go b/test/transakcio/lang.go index 7736b42..5115374 100644 --- a/test/transakcio/lang.go +++ b/test/transakcio/lang.go @@ -5,11 +5,11 @@ import ( "bytes" "fmt" "io" - "log" "sort" "strconv" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/log" ) var eof = rune(0) @@ -29,11 +29,16 @@ var setTypePoolL2 = setType("PoolL2") // typeNewBatch is used for testing purposes only, and represents the // common.TxType of a new batch -var typeNewBatch common.TxType = "TxTypeNewBatch" +var typeNewBatch common.TxType = "InstrTypeNewBatch" // typeNewBlock is used for testing purposes only, and represents the // common.TxType of a new ethereum block -var typeNewBlock common.TxType = "TxTypeNewBlock" +var typeNewBlock common.TxType = "InstrTypeNewBlock" + +// typeRegisterToken is used for testing purposes only, and represents the +// common.TxType of a new Token regsitration +// It has 'nolint:gosec' as the string 'Token' triggers gosec as a potential leaked Token (which is not the case) +var typeRegisterToken common.TxType = "InstrTypeRegisterToken" //nolint:gosec var txTypeCreateAccountDepositCoordinator common.TxType = "TypeCreateAccountDepositCoordinator" @@ -63,7 +68,6 @@ type parsedSet struct { // type string instructions []instruction accounts []string - tokenIDs []common.TokenID } func (i instruction) String() string { @@ -294,7 +298,28 @@ func (p *parser) parseLine(setType setType) (*instruction, error) { } else { return c, fmt.Errorf("Invalid set type: '%s'. Valid set types: 'Blockchain', 'PoolL2'", lit) } + } else if lit == "RegisterToken" { + if err := p.expectChar(c, "("); err != nil { + return c, err + } + _, lit = p.scanIgnoreWhitespace() + c.literal += lit + tidI, err := strconv.Atoi(lit) + if err != nil { + line, _ := p.s.r.ReadString('\n') + c.literal += line + return c, err + } + c.tokenID = common.TokenID(tidI) + if err := p.expectChar(c, ")"); err != nil { + return c, err + } + c.typ = typeRegisterToken + line, _ := p.s.r.ReadString('\n') + c.literal += line + return c, newEventLine } + if setType == "" { return c, fmt.Errorf("Set type not defined") } @@ -458,10 +483,9 @@ func idxTokenIDToString(idx string, tid common.TokenID) string { // parse parses through reader func (p *parser) parse() (*parsedSet, error) { - instructions := &parsedSet{} + ps := &parsedSet{} i := 0 accounts := make(map[string]bool) - tokenids := make(map[common.TokenID]bool) var setTypeOfSet setType for { instruction, err := p.parseLine(setTypeOfSet) @@ -469,6 +493,9 @@ func (p *parser) parse() (*parsedSet, error) { break } if err == setTypeLine { + if setTypeOfSet != "" { + return ps, fmt.Errorf("Instruction of 'Type: %s' when there is already a previous instruction 'Type: %s' defined", instruction.typ, setTypeOfSet) + } if instruction.typ == "PoolL2" { setTypeOfSet = setTypePoolL2 } else if instruction.typ == "Blockchain" { @@ -484,30 +511,29 @@ func (p *parser) parse() (*parsedSet, error) { continue } if err == newEventLine { + if instruction.typ == typeRegisterToken && instruction.tokenID == common.TokenID(0) { + return ps, fmt.Errorf("RegisterToken can not register TokenID 0") + } i++ - instructions.instructions = append(instructions.instructions, *instruction) + ps.instructions = append(ps.instructions, *instruction) continue } if err != nil { - return instructions, fmt.Errorf("error parsing line %d: %s, err: %s", i, instruction.literal, err.Error()) + return ps, fmt.Errorf("error parsing line %d: %s, err: %s", i, instruction.literal, err.Error()) } if setTypeOfSet == "" { - return instructions, fmt.Errorf("Set type not defined") + return ps, fmt.Errorf("Set type not defined") } - instructions.instructions = append(instructions.instructions, *instruction) + ps.instructions = append(ps.instructions, *instruction) accounts[instruction.from] = true if instruction.typ == common.TxTypeTransfer { // type: Transfer accounts[instruction.to] = true } - tokenids[instruction.tokenID] = true i++ } for a := range accounts { - instructions.accounts = append(instructions.accounts, a) - } - sort.Strings(instructions.accounts) - for tid := range tokenids { - instructions.tokenIDs = append(instructions.tokenIDs, tid) + ps.accounts = append(ps.accounts, a) } - return instructions, nil + sort.Strings(ps.accounts) + return ps, nil } diff --git a/test/transakcio/lang_test.go b/test/transakcio/lang_test.go index d2cc637..2e44ad3 100644 --- a/test/transakcio/lang_test.go +++ b/test/transakcio/lang_test.go @@ -14,6 +14,11 @@ var debug = false func TestParseBlockchainTxs(t *testing.T) { s := ` Type: Blockchain + + // token registrations + RegisterToken(1) + RegisterToken(2) + // deposits Deposit(1) A: 10 Deposit(2) A: 20 @@ -29,6 +34,7 @@ func TestParseBlockchainTxs(t *testing.T) { // set new batch > batch + RegisterToken(3) DepositTransfer(1) A-B: 15, 10 (1) Transfer(1) C-A : 3 (1) @@ -53,9 +59,8 @@ func TestParseBlockchainTxs(t *testing.T) { parser := newParser(strings.NewReader(s)) instructions, err := parser.parse() require.Nil(t, err) - assert.Equal(t, 22, len(instructions.instructions)) + assert.Equal(t, 25, len(instructions.instructions)) assert.Equal(t, 7, len(instructions.accounts)) - assert.Equal(t, 3, len(instructions.tokenIDs)) if debug { fmt.Println(instructions) @@ -64,15 +69,15 @@ func TestParseBlockchainTxs(t *testing.T) { } } - assert.Equal(t, txTypeCreateAccountDepositCoordinator, instructions.instructions[5].typ) - assert.Equal(t, typeNewBatch, instructions.instructions[9].typ) - assert.Equal(t, "Deposit(1)User0:20", instructions.instructions[13].raw()) - assert.Equal(t, "Type: DepositTransfer, From: A, To: B, LoadAmount: 15, Amount: 10, Fee: 1, TokenID: 1\n", instructions.instructions[10].String()) - assert.Equal(t, "Type: Transfer, From: User1, To: User0, Amount: 15, Fee: 1, TokenID: 3\n", instructions.instructions[16].String()) - assert.Equal(t, "Transfer(2)A-B:15(1)", instructions.instructions[12].raw()) - assert.Equal(t, "Type: Transfer, From: A, To: B, Amount: 15, Fee: 1, TokenID: 2\n", instructions.instructions[12].String()) - assert.Equal(t, "Exit(1)A:5", instructions.instructions[21].raw()) - assert.Equal(t, "Type: Exit, From: A, Amount: 5, TokenID: 1\n", instructions.instructions[21].String()) + assert.Equal(t, txTypeCreateAccountDepositCoordinator, instructions.instructions[7].typ) + assert.Equal(t, typeNewBatch, instructions.instructions[11].typ) + assert.Equal(t, "Deposit(1)User0:20", instructions.instructions[16].raw()) + assert.Equal(t, "Type: DepositTransfer, From: A, To: B, LoadAmount: 15, Amount: 10, Fee: 1, TokenID: 1\n", instructions.instructions[13].String()) + assert.Equal(t, "Type: Transfer, From: User1, To: User0, Amount: 15, Fee: 1, TokenID: 3\n", instructions.instructions[19].String()) + assert.Equal(t, "Transfer(2)A-B:15(1)", instructions.instructions[15].raw()) + assert.Equal(t, "Type: Transfer, From: A, To: B, Amount: 15, Fee: 1, TokenID: 2\n", instructions.instructions[15].String()) + assert.Equal(t, "Exit(1)A:5", instructions.instructions[24].raw()) + assert.Equal(t, "Type: Exit, From: A, Amount: 5, TokenID: 1\n", instructions.instructions[24].String()) } func TestParsePoolTxs(t *testing.T) { @@ -90,7 +95,6 @@ func TestParsePoolTxs(t *testing.T) { require.Nil(t, err) assert.Equal(t, 5, len(instructions.instructions)) assert.Equal(t, 4, len(instructions.accounts)) - assert.Equal(t, 2, len(instructions.tokenIDs)) if debug { fmt.Println(instructions) @@ -117,11 +121,12 @@ func TestParseErrors(t *testing.T) { s = ` Type: Blockchain + RegisterToken(1) Deposit(1) A: 10 20 ` parser = newParser(strings.NewReader(s)) _, err = parser.parse() - assert.Equal(t, "error parsing line 2: 20, err: Unexpected Blockchain tx type: 20", err.Error()) + assert.Equal(t, "error parsing line 3: 20, err: Unexpected Blockchain tx type: 20", err.Error()) s = ` Type: Blockchain @@ -141,6 +146,7 @@ func TestParseErrors(t *testing.T) { s = ` Type: Blockchain + RegisterToken(1) Transfer(1) A-B: 10 (255) ` parser = newParser(strings.NewReader(s)) @@ -193,4 +199,17 @@ func TestParseErrors(t *testing.T) { parser = newParser(strings.NewReader(s)) _, err = parser.parse() assert.Equal(t, "error parsing line 0: Type:, err: Invalid set type: 'PoolL1'. Valid set types: 'Blockchain', 'PoolL2'", err.Error()) + s = `Type: PoolL2 + Type: Blockchain` + parser = newParser(strings.NewReader(s)) + _, err = parser.parse() + assert.Equal(t, "Instruction of 'Type: Blockchain' when there is already a previous instruction 'Type: PoolL2' defined", err.Error()) + + s = `Type: Blockchain + RegisterToken(1) + RegisterToken(0) + ` + parser = newParser(strings.NewReader(s)) + _, err = parser.parse() + assert.Equal(t, "RegisterToken can not register TokenID 0", err.Error()) } diff --git a/test/transakcio/sets.go b/test/transakcio/sets.go index 16f0df7..5006c15 100644 --- a/test/transakcio/sets.go +++ b/test/transakcio/sets.go @@ -6,6 +6,9 @@ package transakcio var SetBlockchain0 = ` // Set containing Blockchain transactions Type: Blockchain +RegisterToken(1) +RegisterToken(2) +RegisterToken(3) // deposits TokenID: 1 CreateAccountDeposit(1) A: 50 diff --git a/test/transakcio/sets_test.go b/test/transakcio/sets_test.go index c76da15..39f1cbf 100644 --- a/test/transakcio/sets_test.go +++ b/test/transakcio/sets_test.go @@ -16,6 +16,8 @@ func TestCompileSets(t *testing.T) { assert.Nil(t, err) tc := NewTestContext() - _ = tc.GenerateBlocks(SetBlockchain0) - _ = tc.GenerateBlocks(SetPool0) + _, err = tc.GenerateBlocks(SetBlockchain0) + assert.Nil(t, err) + _, err = tc.GenerateBlocks(SetPool0) + assert.Nil(t, err) } diff --git a/test/transakcio/txs.go b/test/transakcio/txs.go index 21ddc06..3895b1a 100644 --- a/test/transakcio/txs.go +++ b/test/transakcio/txs.go @@ -2,6 +2,7 @@ package transakcio import ( "crypto/ecdsa" + "fmt" "math/big" "strconv" "strings" @@ -10,17 +11,16 @@ import ( ethCommon "github.com/ethereum/go-ethereum/common" ethCrypto "github.com/ethereum/go-ethereum/crypto" "github.com/hermeznetwork/hermez-node/common" - "github.com/hermeznetwork/hermez-node/log" "github.com/iden3/go-iden3-crypto/babyjub" ) // TestContext contains the data of the test type TestContext struct { - Instructions []instruction - accountsNames []string - Users map[string]*User - TokenIDs []common.TokenID - l1CreatedAccounts map[string]*Account + Instructions []instruction + accountsNames []string + Users map[string]*User + lastRegisteredTokenID common.TokenID + l1CreatedAccounts map[string]*Account } // NewTestContext returns a new TestContext @@ -67,16 +67,15 @@ type BatchData struct { // GenerateBlocks returns an array of BlockData for a given set. It uses the // accounts (keys & nonces) of the TestContext. -func (tc *TestContext) GenerateBlocks(set string) []BlockData { +func (tc *TestContext) GenerateBlocks(set string) ([]BlockData, error) { parser := newParser(strings.NewReader(set)) parsedSet, err := parser.parse() if err != nil { - log.Fatal(err) + return nil, err } tc.Instructions = parsedSet.instructions tc.accountsNames = parsedSet.accounts - tc.TokenIDs = parsedSet.tokenIDs tc.generateKeys(tc.accountsNames) @@ -88,6 +87,9 @@ func (tc *TestContext) GenerateBlocks(set string) []BlockData { for _, inst := range parsedSet.instructions { switch inst.typ { case common.TxTypeCreateAccountDeposit, common.TxTypeCreateAccountDepositTransfer, txTypeCreateAccountDepositCoordinator: + if err := tc.checkIfTokenIsRegistered(inst); err != nil { + return nil, err + } tx := common.L1Tx{ // TxID FromEthAddr: tc.Users[inst.from].Addr, @@ -115,8 +117,11 @@ func (tc *TestContext) GenerateBlocks(set string) []BlockData { currBatch.L1UserTxs = append(currBatch.L1UserTxs, tx) } case common.TxTypeDeposit, common.TxTypeDepositTransfer: + if err := tc.checkIfTokenIsRegistered(inst); err != nil { + return nil, err + } if tc.Users[inst.from].Accounts[inst.tokenID] == nil { - log.Fatalf("Deposit at User %s for TokenID %d while account not created yet", inst.from, inst.tokenID) + return nil, fmt.Errorf("Deposit at User %s for TokenID %d while account not created yet", inst.from, inst.tokenID) } tx := common.L1Tx{ // TxID @@ -150,12 +155,15 @@ func (tc *TestContext) GenerateBlocks(set string) []BlockData { } currBatch.L1UserTxs = append(currBatch.L1UserTxs, tx) case common.TxTypeTransfer: + if err := tc.checkIfTokenIsRegistered(inst); err != nil { + return nil, err + } if tc.Users[inst.from].Accounts[inst.tokenID] == nil { - log.Fatalf("Transfer from User %s for TokenID %d while account not created yet", inst.from, inst.tokenID) + return nil, fmt.Errorf("Transfer from User %s for TokenID %d while account not created yet", inst.from, inst.tokenID) } // if account of receiver does not exist, create a new CoordinatorL1Tx creating the account if _, ok := tc.l1CreatedAccounts[idxTokenIDToString(inst.to, inst.tokenID)]; !ok { - log.Fatalf("Can not create Transfer for a non existing account. Batch %d, Instruction: %s", currBatchNum, inst) + return nil, fmt.Errorf("Can not create Transfer for a non existing account. Batch %d, Instruction: %s", currBatchNum, inst) } tc.Users[inst.from].Accounts[inst.tokenID].Nonce++ tx := common.L2Tx{ @@ -168,13 +176,16 @@ func (tc *TestContext) GenerateBlocks(set string) []BlockData { } nTx, err := common.NewPoolL2Tx(tx.PoolL2Tx()) if err != nil { - log.Fatal(err) + return nil, err } tx = nTx.L2Tx() tx.BatchNum = common.BatchNum(currBatchNum) // when converted to PoolL2Tx BatchNum parameter is lost currBatch.L2Txs = append(currBatch.L2Txs, tx) case common.TxTypeExit: + if err := tc.checkIfTokenIsRegistered(inst); err != nil { + return nil, err + } tc.Users[inst.from].Accounts[inst.tokenID].Nonce++ tx := common.L2Tx{ FromIdx: tc.Users[inst.from].Accounts[inst.tokenID].Idx, @@ -185,11 +196,14 @@ func (tc *TestContext) GenerateBlocks(set string) []BlockData { } nTx, err := common.NewPoolL2Tx(tx.PoolL2Tx()) if err != nil { - log.Fatal(err) + return nil, err } tx = nTx.L2Tx() currBatch.L2Txs = append(currBatch.L2Txs, tx) case common.TxTypeForceExit: + if err := tc.checkIfTokenIsRegistered(inst); err != nil { + return nil, err + } tx := common.L1Tx{ FromIdx: tc.Users[inst.from].Accounts[inst.tokenID].Idx, ToIdx: common.Idx(1), // as is an Exit @@ -208,28 +222,43 @@ func (tc *TestContext) GenerateBlocks(set string) []BlockData { currBatch = BatchData{} blocks = append(blocks, currBlock) currBlock = BlockData{} + case typeRegisterToken: + newToken := common.Token{ + TokenID: inst.tokenID, + EthBlockNum: int64(len(blocks)), + } + if inst.tokenID != tc.lastRegisteredTokenID+1 { + return nil, fmt.Errorf("RegisterToken TokenID should be sequential, expected TokenID: %d, defined TokenID: %d", tc.lastRegisteredTokenID+1, inst.tokenID) + } + tc.lastRegisteredTokenID++ + currBlock.RegisteredTokens = append(currBlock.RegisteredTokens, newToken) default: - log.Fatalf("Unexpected type: %s", inst.typ) + return nil, fmt.Errorf("Unexpected type: %s", inst.typ) } } currBlock.Batches = append(currBlock.Batches, currBatch) blocks = append(blocks, currBlock) - return blocks + return blocks, nil +} +func (tc *TestContext) checkIfTokenIsRegistered(inst instruction) error { + if inst.tokenID > tc.lastRegisteredTokenID { + return fmt.Errorf("Can not process %s: TokenID %d not registered, last registered TokenID: %d", inst.typ, inst.tokenID, tc.lastRegisteredTokenID) + } + return nil } // GeneratePoolL2Txs returns an array of common.PoolL2Tx from a given set. It // uses the accounts (keys & nonces) of the TestContext. -func (tc *TestContext) GeneratePoolL2Txs(set string) []common.PoolL2Tx { +func (tc *TestContext) GeneratePoolL2Txs(set string) ([]common.PoolL2Tx, error) { parser := newParser(strings.NewReader(set)) parsedSet, err := parser.parse() if err != nil { - log.Fatal(err) + return nil, err } tc.Instructions = parsedSet.instructions tc.accountsNames = parsedSet.accounts - tc.TokenIDs = parsedSet.tokenIDs tc.generateKeys(tc.accountsNames) @@ -238,10 +267,10 @@ func (tc *TestContext) GeneratePoolL2Txs(set string) []common.PoolL2Tx { switch inst.typ { case common.TxTypeTransfer: if tc.Users[inst.from].Accounts[inst.tokenID] == nil { - log.Fatalf("Transfer from User %s for TokenID %d while account not created yet", inst.from, inst.tokenID) + return nil, fmt.Errorf("Transfer from User %s for TokenID %d while account not created yet", inst.from, inst.tokenID) } if tc.Users[inst.to].Accounts[inst.tokenID] == nil { - log.Fatalf("Transfer to User %s for TokenID %d while account not created yet", inst.to, inst.tokenID) + return nil, fmt.Errorf("Transfer to User %s for TokenID %d while account not created yet", inst.to, inst.tokenID) } tc.Users[inst.from].Accounts[inst.tokenID].Nonce++ // if account of receiver does not exist, don't use @@ -263,13 +292,13 @@ func (tc *TestContext) GeneratePoolL2Txs(set string) []common.PoolL2Tx { } nTx, err := common.NewPoolL2Tx(&tx) if err != nil { - log.Fatal(err) + return nil, err } tx = *nTx // perform signature and set it to tx.Signature toSign, err := tx.HashToSign() if err != nil { - log.Fatal(err) + return nil, err } sig := tc.Users[inst.to].BJJ.SignPoseidon(toSign) tx.Signature = sig @@ -287,11 +316,11 @@ func (tc *TestContext) GeneratePoolL2Txs(set string) []common.PoolL2Tx { } txs = append(txs, tx) default: - log.Fatalf("instruction type unrecognized: %s", inst.typ) + return nil, fmt.Errorf("instruction type unrecognized: %s", inst.typ) } } - return txs + return txs, nil } // generateKeys generates BabyJubJub & Address keys for the given list of diff --git a/test/transakcio/txs_test.go b/test/transakcio/txs_test.go index 957d814..88f7748 100644 --- a/test/transakcio/txs_test.go +++ b/test/transakcio/txs_test.go @@ -6,11 +6,15 @@ import ( "github.com/hermeznetwork/hermez-node/common" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestGenerateBlocks(t *testing.T) { set := ` Type: Blockchain + RegisterToken(1) + RegisterToken(2) + RegisterToken(3) CreateAccountDeposit(1) A: 10 CreateAccountDeposit(2) A: 20 @@ -51,7 +55,8 @@ func TestGenerateBlocks(t *testing.T) { Exit(1) A: 5 ` tc := NewTestContext() - blocks := tc.GenerateBlocks(set) + blocks, err := tc.GenerateBlocks(set) + require.Nil(t, err) assert.Equal(t, 2, len(blocks)) assert.Equal(t, 3, len(blocks[0].Batches)) assert.Equal(t, 1, len(blocks[1].Batches)) @@ -136,6 +141,9 @@ func (tc *TestContext) checkL2TxParams(t *testing.T, tx common.L2Tx, typ common. func TestGeneratePoolL2Txs(t *testing.T) { set := ` Type: Blockchain + RegisterToken(1) + RegisterToken(2) + RegisterToken(3) CreateAccountDeposit(1) A: 10 CreateAccountDeposit(2) A: 20 @@ -149,7 +157,8 @@ func TestGeneratePoolL2Txs(t *testing.T) { CreateAccountDeposit(2) D: 0 ` tc := NewTestContext() - _ = tc.GenerateBlocks(set) + _, err := tc.GenerateBlocks(set) + require.Nil(t, err) set = ` Type: PoolL2 PoolTransfer(1) A-B: 6 (1) @@ -162,7 +171,8 @@ func TestGeneratePoolL2Txs(t *testing.T) { PoolTransfer(2) B-D: 3 (1) PoolExit(1) A: 3 ` - poolL2Txs := tc.GeneratePoolL2Txs(set) + poolL2Txs, err := tc.GeneratePoolL2Txs(set) + require.Nil(t, err) assert.Equal(t, 9, len(poolL2Txs)) assert.Equal(t, common.TxTypeTransfer, poolL2Txs[0].Type) assert.Equal(t, common.TxTypeExit, poolL2Txs[8].Type) @@ -182,8 +192,47 @@ func TestGeneratePoolL2Txs(t *testing.T) { PoolTransfer(1) B-C: 3 (1) PoolTransfer(1) A-C: 3 (1) ` - poolL2Txs = tc.GeneratePoolL2Txs(set) + poolL2Txs, err = tc.GeneratePoolL2Txs(set) + require.Nil(t, err) assert.Equal(t, common.Nonce(4), poolL2Txs[0].Nonce) assert.Equal(t, common.Nonce(2), poolL2Txs[1].Nonce) assert.Equal(t, common.Nonce(5), poolL2Txs[2].Nonce) } + +func TestGenerateErrors(t *testing.T) { + // unregistered token + set := `Type: Blockchain + CreateAccountDeposit(1) A: 5 + ` + tc := NewTestContext() + _, err := tc.GenerateBlocks(set) + assert.Equal(t, "Can not process CreateAccountDeposit: TokenID 1 not registered, last registered TokenID: 0", err.Error()) + + // ensure RegisterToken sequentiality and not using 0 + set = ` + Type: Blockchain + RegisterToken(0) + ` + tc = NewTestContext() + _, err = tc.GenerateBlocks(set) + require.Equal(t, "RegisterToken can not register TokenID 0", err.Error()) + + set = ` + Type: Blockchain + RegisterToken(2) + ` + tc = NewTestContext() + _, err = tc.GenerateBlocks(set) + require.Equal(t, "RegisterToken TokenID should be sequential, expected TokenID: 1, defined TokenID: 2", err.Error()) + + set = ` + Type: Blockchain + RegisterToken(1) + RegisterToken(2) + RegisterToken(3) + RegisterToken(5) + ` + tc = NewTestContext() + _, err = tc.GenerateBlocks(set) + require.Equal(t, "RegisterToken TokenID should be sequential, expected TokenID: 4, defined TokenID: 5", err.Error()) +}