mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-07 03:16:45 +01:00
Merge pull request #199 from hermeznetwork/feature/tkcio-tokenregister
Add transakcio Token Register instructions parser
This commit is contained in:
@@ -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
|
tx.TokenID = acc.TokenID
|
||||||
// that the Synchronizer works with, but does not need to be
|
|
||||||
// defined because is not used later for the L2Txs processing
|
|
||||||
// (Transfer & Exit)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch tx.Type {
|
switch tx.Type {
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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)
|
ps.accounts = append(ps.accounts, a)
|
||||||
}
|
}
|
||||||
sort.Strings(instructions.accounts)
|
sort.Strings(ps.accounts)
|
||||||
for tid := range tokenids {
|
return ps, nil
|
||||||
instructions.tokenIDs = append(instructions.tokenIDs, tid)
|
|
||||||
}
|
|
||||||
return instructions, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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, txTypeCreateAccountDepositCoordinator, instructions.instructions[7].typ)
|
||||||
assert.Equal(t, typeNewBatch, instructions.instructions[9].typ)
|
assert.Equal(t, typeNewBatch, instructions.instructions[11].typ)
|
||||||
assert.Equal(t, "Deposit(1)User0:20", instructions.instructions[13].raw())
|
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[10].String())
|
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[16].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[12].raw())
|
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[12].String())
|
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[21].raw())
|
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[21].String())
|
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())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ func TestCompileSets(t *testing.T) {
|
|||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
tc := NewTestContext()
|
tc := NewTestContext()
|
||||||
_ = tc.GenerateBlocks(SetBlockchain0)
|
_, err = tc.GenerateBlocks(SetBlockchain0)
|
||||||
_ = tc.GenerateBlocks(SetPool0)
|
assert.Nil(t, err)
|
||||||
|
_, err = tc.GenerateBlocks(SetPool0)
|
||||||
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
Instructions []instruction
|
||||||
accountsNames []string
|
accountsNames []string
|
||||||
Users map[string]*User
|
Users map[string]*User
|
||||||
TokenIDs []common.TokenID
|
lastRegisteredTokenID common.TokenID
|
||||||
l1CreatedAccounts map[string]*Account
|
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
|
||||||
|
|||||||
@@ -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())
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user