Browse Source

Merge pull request #199 from hermeznetwork/feature/tkcio-tokenregister

Add transakcio Token Register instructions parser
feature/sql-semaphore1
Eduard S 4 years ago
committed by GitHub
parent
commit
b6ebbbaf95
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 192 additions and 66 deletions
  1. +1
    -4
      db/statedb/txprocessors.go
  2. +2
    -1
      db/statedb/txprocessors_test.go
  3. +43
    -17
      test/transakcio/lang.go
  4. +32
    -13
      test/transakcio/lang_test.go
  5. +3
    -0
      test/transakcio/sets.go
  6. +4
    -2
      test/transakcio/sets_test.go
  7. +54
    -25
      test/transakcio/txs.go
  8. +53
    -4
      test/transakcio/txs_test.go

+ 1
- 4
db/statedb/txprocessors.go

@ -366,10 +366,7 @@ func (s *StateDB) processL2Tx(exitTree *merkletree.MerkleTree, tx *common.PoolL2
return nil, nil, false, err return nil, nil, false, err
} }
tx.Nonce = acc.Nonce 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 { switch tx.Type {

+ 2
- 1
db/statedb/txprocessors_test.go

@ -22,7 +22,8 @@ func TestProcessTxsSynchronizer(t *testing.T) {
// generate test transactions from test.SetTest0 code // generate test transactions from test.SetTest0 code
tc := transakcio.NewTestContext() 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, 29, len(blocks[0].Batches[0].L1UserTxs))
assert.Equal(t, 0, len(blocks[0].Batches[0].L1CoordinatorTxs)) assert.Equal(t, 0, len(blocks[0].Batches[0].L1CoordinatorTxs))

+ 43
- 17
test/transakcio/lang.go

@ -5,11 +5,11 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"io" "io"
"log"
"sort" "sort"
"strconv" "strconv"
"github.com/hermeznetwork/hermez-node/common" "github.com/hermeznetwork/hermez-node/common"
"github.com/hermeznetwork/hermez-node/log"
) )
var eof = rune(0) var eof = rune(0)
@ -29,11 +29,16 @@ var setTypePoolL2 = setType("PoolL2")
// typeNewBatch is used for testing purposes only, and represents the // typeNewBatch is used for testing purposes only, and represents the
// common.TxType of a new batch // 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 // typeNewBlock is used for testing purposes only, and represents the
// common.TxType of a new ethereum block // 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" var txTypeCreateAccountDepositCoordinator common.TxType = "TypeCreateAccountDepositCoordinator"
@ -63,7 +68,6 @@ type parsedSet struct {
// type string // type string
instructions []instruction instructions []instruction
accounts []string accounts []string
tokenIDs []common.TokenID
} }
func (i instruction) String() string { func (i instruction) String() string {
@ -294,7 +298,28 @@ func (p *parser) parseLine(setType setType) (*instruction, error) {
} else { } else {
return c, fmt.Errorf("Invalid set type: '%s'. Valid set types: 'Blockchain', 'PoolL2'", lit) 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 == "" { if setType == "" {
return c, fmt.Errorf("Set type not defined") return c, fmt.Errorf("Set type not defined")
} }
@ -458,10 +483,9 @@ func idxTokenIDToString(idx string, tid common.TokenID) string {
// parse parses through reader // parse parses through reader
func (p *parser) parse() (*parsedSet, error) { func (p *parser) parse() (*parsedSet, error) {
instructions := &parsedSet{}
ps := &parsedSet{}
i := 0 i := 0
accounts := make(map[string]bool) accounts := make(map[string]bool)
tokenids := make(map[common.TokenID]bool)
var setTypeOfSet setType var setTypeOfSet setType
for { for {
instruction, err := p.parseLine(setTypeOfSet) instruction, err := p.parseLine(setTypeOfSet)
@ -469,6 +493,9 @@ func (p *parser) parse() (*parsedSet, error) {
break break
} }
if err == setTypeLine { 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" { if instruction.typ == "PoolL2" {
setTypeOfSet = setTypePoolL2 setTypeOfSet = setTypePoolL2
} else if instruction.typ == "Blockchain" { } else if instruction.typ == "Blockchain" {
@ -484,30 +511,29 @@ func (p *parser) parse() (*parsedSet, error) {
continue continue
} }
if err == newEventLine { if err == newEventLine {
if instruction.typ == typeRegisterToken && instruction.tokenID == common.TokenID(0) {
return ps, fmt.Errorf("RegisterToken can not register TokenID 0")
}
i++ i++
instructions.instructions = append(instructions.instructions, *instruction)
ps.instructions = append(ps.instructions, *instruction)
continue continue
} }
if err != nil { 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 == "" { 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 accounts[instruction.from] = true
if instruction.typ == common.TxTypeTransfer { // type: Transfer if instruction.typ == common.TxTypeTransfer { // type: Transfer
accounts[instruction.to] = true accounts[instruction.to] = true
} }
tokenids[instruction.tokenID] = true
i++ i++
} }
for a := range accounts { 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
} }

+ 32
- 13
test/transakcio/lang_test.go

@ -14,6 +14,11 @@ var debug = false
func TestParseBlockchainTxs(t *testing.T) { func TestParseBlockchainTxs(t *testing.T) {
s := ` s := `
Type: Blockchain Type: Blockchain
// token registrations
RegisterToken(1)
RegisterToken(2)
// deposits // deposits
Deposit(1) A: 10 Deposit(1) A: 10
Deposit(2) A: 20 Deposit(2) A: 20
@ -29,6 +34,7 @@ func TestParseBlockchainTxs(t *testing.T) {
// set new batch // set new batch
> batch > batch
RegisterToken(3)
DepositTransfer(1) A-B: 15, 10 (1) DepositTransfer(1) A-B: 15, 10 (1)
Transfer(1) C-A : 3 (1) Transfer(1) C-A : 3 (1)
@ -53,9 +59,8 @@ func TestParseBlockchainTxs(t *testing.T) {
parser := newParser(strings.NewReader(s)) parser := newParser(strings.NewReader(s))
instructions, err := parser.parse() instructions, err := parser.parse()
require.Nil(t, err) 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, 7, len(instructions.accounts))
assert.Equal(t, 3, len(instructions.tokenIDs))
if debug { if debug {
fmt.Println(instructions) 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) { func TestParsePoolTxs(t *testing.T) {
@ -90,7 +95,6 @@ func TestParsePoolTxs(t *testing.T) {
require.Nil(t, err) require.Nil(t, err)
assert.Equal(t, 5, len(instructions.instructions)) assert.Equal(t, 5, len(instructions.instructions))
assert.Equal(t, 4, len(instructions.accounts)) assert.Equal(t, 4, len(instructions.accounts))
assert.Equal(t, 2, len(instructions.tokenIDs))
if debug { if debug {
fmt.Println(instructions) fmt.Println(instructions)
@ -117,11 +121,12 @@ func TestParseErrors(t *testing.T) {
s = ` s = `
Type: Blockchain Type: Blockchain
RegisterToken(1)
Deposit(1) A: 10 20 Deposit(1) A: 10 20
` `
parser = newParser(strings.NewReader(s)) parser = newParser(strings.NewReader(s))
_, err = parser.parse() _, 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 = ` s = `
Type: Blockchain Type: Blockchain
@ -141,6 +146,7 @@ func TestParseErrors(t *testing.T) {
s = ` s = `
Type: Blockchain Type: Blockchain
RegisterToken(1)
Transfer(1) A-B: 10 (255) Transfer(1) A-B: 10 (255)
` `
parser = newParser(strings.NewReader(s)) parser = newParser(strings.NewReader(s))
@ -193,4 +199,17 @@ func TestParseErrors(t *testing.T) {
parser = newParser(strings.NewReader(s)) parser = newParser(strings.NewReader(s))
_, err = parser.parse() _, err = parser.parse()
assert.Equal(t, "error parsing line 0: Type:, err: Invalid set type: 'PoolL1'. Valid set types: 'Blockchain', 'PoolL2'", err.Error()) 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())
} }

+ 3
- 0
test/transakcio/sets.go

@ -6,6 +6,9 @@ package transakcio
var SetBlockchain0 = ` var SetBlockchain0 = `
// Set containing Blockchain transactions // Set containing Blockchain transactions
Type: Blockchain Type: Blockchain
RegisterToken(1)
RegisterToken(2)
RegisterToken(3)
// deposits TokenID: 1 // deposits TokenID: 1
CreateAccountDeposit(1) A: 50 CreateAccountDeposit(1) A: 50

+ 4
- 2
test/transakcio/sets_test.go

@ -16,6 +16,8 @@ func TestCompileSets(t *testing.T) {
assert.Nil(t, err) assert.Nil(t, err)
tc := NewTestContext() tc := NewTestContext()
_ = tc.GenerateBlocks(SetBlockchain0)
_ = tc.GenerateBlocks(SetPool0)
_, err = tc.GenerateBlocks(SetBlockchain0)
assert.Nil(t, err)
_, err = tc.GenerateBlocks(SetPool0)
assert.Nil(t, err)
} }

+ 54
- 25
test/transakcio/txs.go

@ -2,6 +2,7 @@ package transakcio
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
"fmt"
"math/big" "math/big"
"strconv" "strconv"
"strings" "strings"
@ -10,17 +11,16 @@ import (
ethCommon "github.com/ethereum/go-ethereum/common" ethCommon "github.com/ethereum/go-ethereum/common"
ethCrypto "github.com/ethereum/go-ethereum/crypto" ethCrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/hermeznetwork/hermez-node/common" "github.com/hermeznetwork/hermez-node/common"
"github.com/hermeznetwork/hermez-node/log"
"github.com/iden3/go-iden3-crypto/babyjub" "github.com/iden3/go-iden3-crypto/babyjub"
) )
// TestContext contains the data of the test // TestContext contains the data of the test
type TestContext struct { 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 // 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 // GenerateBlocks returns an array of BlockData for a given set. It uses the
// accounts (keys & nonces) of the TestContext. // 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)) parser := newParser(strings.NewReader(set))
parsedSet, err := parser.parse() parsedSet, err := parser.parse()
if err != nil { if err != nil {
log.Fatal(err)
return nil, err
} }
tc.Instructions = parsedSet.instructions tc.Instructions = parsedSet.instructions
tc.accountsNames = parsedSet.accounts tc.accountsNames = parsedSet.accounts
tc.TokenIDs = parsedSet.tokenIDs
tc.generateKeys(tc.accountsNames) tc.generateKeys(tc.accountsNames)
@ -88,6 +87,9 @@ func (tc *TestContext) GenerateBlocks(set string) []BlockData {
for _, inst := range parsedSet.instructions { for _, inst := range parsedSet.instructions {
switch inst.typ { switch inst.typ {
case common.TxTypeCreateAccountDeposit, common.TxTypeCreateAccountDepositTransfer, txTypeCreateAccountDepositCoordinator: case common.TxTypeCreateAccountDeposit, common.TxTypeCreateAccountDepositTransfer, txTypeCreateAccountDepositCoordinator:
if err := tc.checkIfTokenIsRegistered(inst); err != nil {
return nil, err
}
tx := common.L1Tx{ tx := common.L1Tx{
// TxID // TxID
FromEthAddr: tc.Users[inst.from].Addr, FromEthAddr: tc.Users[inst.from].Addr,
@ -115,8 +117,11 @@ func (tc *TestContext) GenerateBlocks(set string) []BlockData {
currBatch.L1UserTxs = append(currBatch.L1UserTxs, tx) currBatch.L1UserTxs = append(currBatch.L1UserTxs, tx)
} }
case common.TxTypeDeposit, common.TxTypeDepositTransfer: case common.TxTypeDeposit, common.TxTypeDepositTransfer:
if err := tc.checkIfTokenIsRegistered(inst); err != nil {
return nil, err
}
if tc.Users[inst.from].Accounts[inst.tokenID] == nil { 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{ tx := common.L1Tx{
// TxID // TxID
@ -150,12 +155,15 @@ func (tc *TestContext) GenerateBlocks(set string) []BlockData {
} }
currBatch.L1UserTxs = append(currBatch.L1UserTxs, tx) currBatch.L1UserTxs = append(currBatch.L1UserTxs, tx)
case common.TxTypeTransfer: case common.TxTypeTransfer:
if err := tc.checkIfTokenIsRegistered(inst); err != nil {
return nil, err
}
if tc.Users[inst.from].Accounts[inst.tokenID] == nil { 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 account of receiver does not exist, create a new CoordinatorL1Tx creating the account
if _, ok := tc.l1CreatedAccounts[idxTokenIDToString(inst.to, inst.tokenID)]; !ok { 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++ tc.Users[inst.from].Accounts[inst.tokenID].Nonce++
tx := common.L2Tx{ tx := common.L2Tx{
@ -168,13 +176,16 @@ func (tc *TestContext) GenerateBlocks(set string) []BlockData {
} }
nTx, err := common.NewPoolL2Tx(tx.PoolL2Tx()) nTx, err := common.NewPoolL2Tx(tx.PoolL2Tx())
if err != nil { if err != nil {
log.Fatal(err)
return nil, err
} }
tx = nTx.L2Tx() tx = nTx.L2Tx()
tx.BatchNum = common.BatchNum(currBatchNum) // when converted to PoolL2Tx BatchNum parameter is lost tx.BatchNum = common.BatchNum(currBatchNum) // when converted to PoolL2Tx BatchNum parameter is lost
currBatch.L2Txs = append(currBatch.L2Txs, tx) currBatch.L2Txs = append(currBatch.L2Txs, tx)
case common.TxTypeExit: case common.TxTypeExit:
if err := tc.checkIfTokenIsRegistered(inst); err != nil {
return nil, err
}
tc.Users[inst.from].Accounts[inst.tokenID].Nonce++ tc.Users[inst.from].Accounts[inst.tokenID].Nonce++
tx := common.L2Tx{ tx := common.L2Tx{
FromIdx: tc.Users[inst.from].Accounts[inst.tokenID].Idx, 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()) nTx, err := common.NewPoolL2Tx(tx.PoolL2Tx())
if err != nil { if err != nil {
log.Fatal(err)
return nil, err
} }
tx = nTx.L2Tx() tx = nTx.L2Tx()
currBatch.L2Txs = append(currBatch.L2Txs, tx) currBatch.L2Txs = append(currBatch.L2Txs, tx)
case common.TxTypeForceExit: case common.TxTypeForceExit:
if err := tc.checkIfTokenIsRegistered(inst); err != nil {
return nil, err
}
tx := common.L1Tx{ tx := common.L1Tx{
FromIdx: tc.Users[inst.from].Accounts[inst.tokenID].Idx, FromIdx: tc.Users[inst.from].Accounts[inst.tokenID].Idx,
ToIdx: common.Idx(1), // as is an Exit ToIdx: common.Idx(1), // as is an Exit
@ -208,28 +222,43 @@ func (tc *TestContext) GenerateBlocks(set string) []BlockData {
currBatch = BatchData{} currBatch = BatchData{}
blocks = append(blocks, currBlock) blocks = append(blocks, currBlock)
currBlock = BlockData{} 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: default:
log.Fatalf("Unexpected type: %s", inst.typ)
return nil, fmt.Errorf("Unexpected type: %s", inst.typ)
} }
} }
currBlock.Batches = append(currBlock.Batches, currBatch) currBlock.Batches = append(currBlock.Batches, currBatch)
blocks = append(blocks, currBlock) 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 // GeneratePoolL2Txs returns an array of common.PoolL2Tx from a given set. It
// uses the accounts (keys & nonces) of the TestContext. // 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)) parser := newParser(strings.NewReader(set))
parsedSet, err := parser.parse() parsedSet, err := parser.parse()
if err != nil { if err != nil {
log.Fatal(err)
return nil, err
} }
tc.Instructions = parsedSet.instructions tc.Instructions = parsedSet.instructions
tc.accountsNames = parsedSet.accounts tc.accountsNames = parsedSet.accounts
tc.TokenIDs = parsedSet.tokenIDs
tc.generateKeys(tc.accountsNames) tc.generateKeys(tc.accountsNames)
@ -238,10 +267,10 @@ func (tc *TestContext) GeneratePoolL2Txs(set string) []common.PoolL2Tx {
switch inst.typ { switch inst.typ {
case common.TxTypeTransfer: case common.TxTypeTransfer:
if tc.Users[inst.from].Accounts[inst.tokenID] == nil { 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 { 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++ tc.Users[inst.from].Accounts[inst.tokenID].Nonce++
// if account of receiver does not exist, don't use // 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) nTx, err := common.NewPoolL2Tx(&tx)
if err != nil { if err != nil {
log.Fatal(err)
return nil, err
} }
tx = *nTx tx = *nTx
// perform signature and set it to tx.Signature // perform signature and set it to tx.Signature
toSign, err := tx.HashToSign() toSign, err := tx.HashToSign()
if err != nil { if err != nil {
log.Fatal(err)
return nil, err
} }
sig := tc.Users[inst.to].BJJ.SignPoseidon(toSign) sig := tc.Users[inst.to].BJJ.SignPoseidon(toSign)
tx.Signature = sig tx.Signature = sig
@ -287,11 +316,11 @@ func (tc *TestContext) GeneratePoolL2Txs(set string) []common.PoolL2Tx {
} }
txs = append(txs, tx) txs = append(txs, tx)
default: 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 // generateKeys generates BabyJubJub & Address keys for the given list of

+ 53
- 4
test/transakcio/txs_test.go

@ -6,11 +6,15 @@ import (
"github.com/hermeznetwork/hermez-node/common" "github.com/hermeznetwork/hermez-node/common"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestGenerateBlocks(t *testing.T) { func TestGenerateBlocks(t *testing.T) {
set := ` set := `
Type: Blockchain Type: Blockchain
RegisterToken(1)
RegisterToken(2)
RegisterToken(3)
CreateAccountDeposit(1) A: 10 CreateAccountDeposit(1) A: 10
CreateAccountDeposit(2) A: 20 CreateAccountDeposit(2) A: 20
@ -51,7 +55,8 @@ func TestGenerateBlocks(t *testing.T) {
Exit(1) A: 5 Exit(1) A: 5
` `
tc := NewTestContext() tc := NewTestContext()
blocks := tc.GenerateBlocks(set)
blocks, err := tc.GenerateBlocks(set)
require.Nil(t, err)
assert.Equal(t, 2, len(blocks)) assert.Equal(t, 2, len(blocks))
assert.Equal(t, 3, len(blocks[0].Batches)) assert.Equal(t, 3, len(blocks[0].Batches))
assert.Equal(t, 1, len(blocks[1].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) { func TestGeneratePoolL2Txs(t *testing.T) {
set := ` set := `
Type: Blockchain Type: Blockchain
RegisterToken(1)
RegisterToken(2)
RegisterToken(3)
CreateAccountDeposit(1) A: 10 CreateAccountDeposit(1) A: 10
CreateAccountDeposit(2) A: 20 CreateAccountDeposit(2) A: 20
@ -149,7 +157,8 @@ func TestGeneratePoolL2Txs(t *testing.T) {
CreateAccountDeposit(2) D: 0 CreateAccountDeposit(2) D: 0
` `
tc := NewTestContext() tc := NewTestContext()
_ = tc.GenerateBlocks(set)
_, err := tc.GenerateBlocks(set)
require.Nil(t, err)
set = ` set = `
Type: PoolL2 Type: PoolL2
PoolTransfer(1) A-B: 6 (1) PoolTransfer(1) A-B: 6 (1)
@ -162,7 +171,8 @@ func TestGeneratePoolL2Txs(t *testing.T) {
PoolTransfer(2) B-D: 3 (1) PoolTransfer(2) B-D: 3 (1)
PoolExit(1) A: 3 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, 9, len(poolL2Txs))
assert.Equal(t, common.TxTypeTransfer, poolL2Txs[0].Type) assert.Equal(t, common.TxTypeTransfer, poolL2Txs[0].Type)
assert.Equal(t, common.TxTypeExit, poolL2Txs[8].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) B-C: 3 (1)
PoolTransfer(1) A-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(4), poolL2Txs[0].Nonce)
assert.Equal(t, common.Nonce(2), poolL2Txs[1].Nonce) assert.Equal(t, common.Nonce(2), poolL2Txs[1].Nonce)
assert.Equal(t, common.Nonce(5), poolL2Txs[2].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())
}

Loading…
Cancel
Save