From b40bccfc0037e965e1908f74783c0a256724f00b Mon Sep 17 00:00:00 2001 From: arnaucube Date: Wed, 7 Oct 2020 17:21:02 +0200 Subject: [PATCH] Add Transakcio block&batch txs generationfrom code --- log/log.go | 21 ++- test/lang.go | 79 +++++++++-- test/lang_test.go | 41 ++++-- test/sets_test.go | 2 +- test/txs.go | 327 ++++++++++++++++++++++++++-------------------- test/txs_test.go | 136 +++++++++++++++++-- test/utils.go | 12 ++ 7 files changed, 437 insertions(+), 181 deletions(-) create mode 100644 test/utils.go diff --git a/log/log.go b/log/log.go index 08b4e09..ae886e0 100644 --- a/log/log.go +++ b/log/log.go @@ -80,11 +80,16 @@ func Warn(args ...interface{}) { log.Warn(args...) } -// Error calls log.Error and stores the error message into the ErrorFile +// Error calls log.Error func Error(args ...interface{}) { log.Error(args...) } +// Fatal calls log.Fatal +func Fatal(args ...interface{}) { + log.Fatal(args...) +} + // Debugf calls log.Debugf func Debugf(template string, args ...interface{}) { log.Debugf(template, args...) @@ -100,6 +105,11 @@ func Warnf(template string, args ...interface{}) { log.Warnf(template, args...) } +// Fatalf calls log.Warnf +func Fatalf(template string, args ...interface{}) { + log.Fatalf(template, args...) +} + // Errorf calls log.Errorf and stores the error message into the ErrorFile func Errorf(template string, args ...interface{}) { log.Errorf(template, args...) @@ -120,7 +130,12 @@ func Warnw(template string, kv ...interface{}) { log.Warnw(template, kv...) } -// Errorw calls log.Errorw and stores the error message into the ErrorFile +// Errorw calls log.Errorw func Errorw(template string, kv ...interface{}) { - log.Errorw(template, kv...) + log.Fatalw(template, kv...) +} + +// Fatalw calls log.Fatalw +func Fatalw(template string, kv ...interface{}) { + log.Fatalw(template, kv...) } diff --git a/test/lang.go b/test/lang.go index fc06653..9244522 100644 --- a/test/lang.go +++ b/test/lang.go @@ -61,11 +61,15 @@ func (i Instruction) String() string { i.Type == common.TxTypeCreateAccountDepositTransfer { fmt.Fprintf(buf, "To: %s, ", i.To) } - if i.Type == common.TxTypeDepositTransfer || + + if i.Type == common.TxTypeDeposit || + i.Type == common.TxTypeDepositTransfer || i.Type == common.TxTypeCreateAccountDepositTransfer { fmt.Fprintf(buf, "LoadAmount: %d, ", i.LoadAmount) } - fmt.Fprintf(buf, "Amount: %d, ", i.Amount) + if i.Type != common.TxTypeDeposit { + fmt.Fprintf(buf, "Amount: %d, ", i.Amount) + } if i.Type == common.TxTypeTransfer || i.Type == common.TxTypeDepositTransfer || i.Type == common.TxTypeCreateAccountDepositTransfer { @@ -87,11 +91,14 @@ func (i Instruction) Raw() string { fmt.Fprintf(buf, "-%s", i.To) } fmt.Fprintf(buf, ":") - if i.Type == common.TxTypeDepositTransfer || + if i.Type == common.TxTypeDeposit || + i.Type == common.TxTypeDepositTransfer || i.Type == common.TxTypeCreateAccountDepositTransfer { - fmt.Fprintf(buf, "%d,", i.LoadAmount) + fmt.Fprintf(buf, "%d", i.LoadAmount) + } + if i.Type != common.TxTypeDeposit { + fmt.Fprintf(buf, "%d", i.Amount) } - fmt.Fprintf(buf, "%d", i.Amount) if i.Type == common.TxTypeTransfer { fmt.Fprintf(buf, "(%d)", i.Fee) } @@ -237,7 +244,7 @@ func (p *Parser) scanIgnoreWhitespace() (tok token, lit string) { } // parseLine parses the current line -func (p *Parser) parseLine() (*Instruction, error) { +func (p *Parser) parseLine(pool bool) (*Instruction, error) { c := &Instruction{} tok, lit := p.scanIgnoreWhitespace() if tok == EOF { @@ -248,6 +255,9 @@ func (p *Parser) parseLine() (*Instruction, error) { _, _ = p.s.r.ReadString('\n') return nil, errComment } else if lit == ">" { + if pool { + return c, fmt.Errorf("Unexpected '>' at PoolL2Txs set") + } _, lit = p.scanIgnoreWhitespace() if lit == "batch" { _, _ = p.s.r.ReadString('\n') @@ -262,23 +272,58 @@ func (p *Parser) parseLine() (*Instruction, error) { transfering := false switch lit { case "Deposit": + if pool { + return c, fmt.Errorf("Unexpected '%s' at PoolL2Txs set", lit) + } c.Type = common.TxTypeDeposit - case "Exit", "PoolExit": + case "Exit": + if pool { + return c, fmt.Errorf("Unexpected '%s' at PoolL2Txs set", lit) + } c.Type = common.TxTypeExit - case "Transfer", "PoolTransfer": + case "PoolExit": + if !pool { + return c, fmt.Errorf("Unexpected '%s' at BlockchainTxs set", lit) + } + c.Type = common.TxTypeExit + case "Transfer": + if pool { + return c, fmt.Errorf("Unexpected '%s' at PoolL2Txs set", lit) + } + c.Type = common.TxTypeTransfer + transfering = true + case "PoolTransfer": + if !pool { + return c, fmt.Errorf("Unexpected '%s' at BlockchainTxs set", lit) + } c.Type = common.TxTypeTransfer transfering = true case "CreateAccountDeposit": + if pool { + return c, fmt.Errorf("Unexpected '%s' at PoolL2Txs set", lit) + } c.Type = common.TxTypeCreateAccountDeposit case "CreateAccountDepositTransfer": + if pool { + return c, fmt.Errorf("Unexpected '%s' at PoolL2Txs set", lit) + } c.Type = common.TxTypeCreateAccountDepositTransfer transfering = true case "DepositTransfer": + if pool { + return c, fmt.Errorf("Unexpected '%s' at PoolL2Txs set", lit) + } c.Type = common.TxTypeDepositTransfer transfering = true case "ForceTransfer": + if pool { + return c, fmt.Errorf("Unexpected '%s' at PoolL2Txs set", lit) + } c.Type = common.TxTypeForceTransfer case "ForceExit": + if pool { + return c, fmt.Errorf("Unexpected '%s' at PoolL2Txs set", lit) + } c.Type = common.TxTypeForceExit default: return c, fmt.Errorf("Unexpected tx type: %s", lit) @@ -304,9 +349,9 @@ func (p *Parser) parseLine() (*Instruction, error) { c.From = lit _, lit = p.scanIgnoreWhitespace() c.Literal += lit - if lit == "-" { - if !transfering { - return c, fmt.Errorf("To defined, but not type {Transfer, CreateAccountDepositTransfer, DepositTransfer}") + if transfering { + if lit != "-" { + return c, fmt.Errorf("Expected '-', found '%s'", lit) } _, lit = p.scanIgnoreWhitespace() c.Literal += lit @@ -321,6 +366,7 @@ func (p *Parser) parseLine() (*Instruction, error) { } if c.Type == common.TxTypeDepositTransfer || c.Type == common.TxTypeCreateAccountDepositTransfer { + // deposit case _, lit = p.scanIgnoreWhitespace() c.Literal += lit loadAmount, err := strconv.Atoi(lit) @@ -342,7 +388,12 @@ func (p *Parser) parseLine() (*Instruction, error) { c.Literal += line return c, err } - c.Amount = uint64(amount) + if c.Type == common.TxTypeDeposit || + c.Type == common.TxTypeCreateAccountDeposit { + c.LoadAmount = uint64(amount) + } else { + c.Amount = uint64(amount) + } if transfering { if err := p.expectChar(c, "("); err != nil { return c, err @@ -389,13 +440,13 @@ func idxTokenIDToString(idx string, tid common.TokenID) string { } // Parse parses through reader -func (p *Parser) Parse() (*ParsedSet, error) { +func (p *Parser) Parse(pool bool) (*ParsedSet, error) { instructions := &ParsedSet{} i := 0 accounts := make(map[string]bool) tokenids := make(map[common.TokenID]bool) for { - instruction, err := p.parseLine() + instruction, err := p.parseLine(pool) if err == errof { break } diff --git a/test/lang_test.go b/test/lang_test.go index da94f1e..31a8200 100644 --- a/test/lang_test.go +++ b/test/lang_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) var debug = false @@ -47,8 +48,8 @@ func TestParseBlockchainTxs(t *testing.T) { ` parser := NewParser(strings.NewReader(s)) - instructions, err := parser.Parse() - assert.Nil(t, err) + instructions, err := parser.Parse(false) + require.Nil(t, err) assert.Equal(t, 20, len(instructions.Instructions)) assert.Equal(t, 10, len(instructions.Accounts)) assert.Equal(t, 3, len(instructions.TokenIDs)) @@ -76,12 +77,12 @@ func TestParsePoolTxs(t *testing.T) { PoolTransfer(2) A-B: 3 (3) PoolTransfer(1) B-D: 3 (1) PoolTransfer(1) C-D: 3 (1) - Exit(1) A: 5 + PoolExit(1) A: 5 ` parser := NewParser(strings.NewReader(s)) - instructions, err := parser.Parse() - assert.Nil(t, err) + instructions, err := parser.Parse(true) + require.Nil(t, err) assert.Equal(t, 5, len(instructions.Instructions)) assert.Equal(t, 6, len(instructions.Accounts)) assert.Equal(t, 2, len(instructions.TokenIDs)) @@ -103,30 +104,46 @@ func TestParsePoolTxs(t *testing.T) { func TestParseErrors(t *testing.T) { s := "Deposit(1) A:: 10" parser := NewParser(strings.NewReader(s)) - _, err := parser.Parse() + _, err := parser.Parse(false) assert.Equal(t, "error parsing line 0: Deposit(1)A:: 10, err: strconv.Atoi: parsing \":\": invalid syntax", err.Error()) s = "Deposit(1) A: 10 20" parser = NewParser(strings.NewReader(s)) - _, err = parser.Parse() + _, err = parser.Parse(false) assert.Equal(t, "error parsing line 1: 20, err: Unexpected tx type: 20", err.Error()) + s = "Transfer(1) A: 10" + parser = NewParser(strings.NewReader(s)) + _, err = parser.Parse(false) + assert.Equal(t, "error parsing line 0: Transfer(1)A:, err: Expected '-', found ':'", err.Error()) + s = "Transfer(1) A B: 10" parser = NewParser(strings.NewReader(s)) - _, err = parser.Parse() - assert.Equal(t, "error parsing line 0: Transfer(1)AB: 10, err: Expected ':', found 'B'", err.Error()) + _, err = parser.Parse(false) + assert.Equal(t, "error parsing line 0: Transfer(1)AB, err: Expected '-', found 'B'", err.Error()) s = "Transfer(1) A-B: 10 (255)" parser = NewParser(strings.NewReader(s)) - _, err = parser.Parse() + _, err = parser.Parse(false) assert.Nil(t, err) s = "Transfer(1) A-B: 10 (256)" parser = NewParser(strings.NewReader(s)) - _, err = parser.Parse() + _, err = parser.Parse(false) assert.Equal(t, "error parsing line 0: Transfer(1)A-B:10(256), err: Fee 256 can not be bigger than 255", err.Error()) + // check that the PoolTransfer & Transfer are only accepted in the + // correct case case (PoolTxs/BlockchainTxs) + s = "Transfer(1) A-B: 10 (1)" + parser = NewParser(strings.NewReader(s)) + _, err = parser.Parse(true) + assert.Equal(t, "error parsing line 0: Transfer, err: Unexpected 'Transfer' at PoolL2Txs set", err.Error()) + s = "PoolTransfer(1) A-B: 10 (1)" + parser = NewParser(strings.NewReader(s)) + _, err = parser.Parse(false) + assert.Equal(t, "error parsing line 0: PoolTransfer, err: Unexpected 'PoolTransfer' at BlockchainTxs set", err.Error()) + s = "> btch" parser = NewParser(strings.NewReader(s)) - _, err = parser.Parse() + _, err = parser.Parse(false) assert.Equal(t, "error parsing line 0: >, err: Unexpected '> btch', expected '> batch' or '> block'", err.Error()) } diff --git a/test/sets_test.go b/test/sets_test.go index 46375d5..85102aa 100644 --- a/test/sets_test.go +++ b/test/sets_test.go @@ -9,6 +9,6 @@ import ( func TestCompileSets(t *testing.T) { parser := NewParser(strings.NewReader(SetTest0)) - _, err := parser.Parse() + _, err := parser.Parse(false) assert.Nil(t, err) } diff --git a/test/txs.go b/test/txs.go index d9b5f42..423dd3f 100644 --- a/test/txs.go +++ b/test/txs.go @@ -16,6 +16,7 @@ import ( "github.com/stretchr/testify/require" ) +// TestContext contains the data of the test type TestContext struct { t *testing.T Instructions []Instruction @@ -25,6 +26,7 @@ type TestContext struct { l1CreatedAccounts map[string]*Account } +// NewTestContext returns a new TestContext func NewTestContext(t *testing.T) *TestContext { return &TestContext{ t: t, @@ -41,16 +43,193 @@ type Account struct { Nonce common.Nonce } -// func (tc *TestContext) GenerateBlocks() []BlockData { -// -// return nil -// } +// BlockData contains the information of a Block +type BlockData struct { + block *common.Block // ethereum block + // L1UserTxs that were submitted in the block + L1UserTxs []common.L1Tx + Batches []BatchData + RegisteredTokens []common.Token +} + +// BatchData contains the information of a Batch +type BatchData struct { + L1Batch bool // TODO: Remove once Batch.ForgeL1TxsNum is a pointer + // L1UserTxs that were forged in the batch + L1UserTxs []common.L1Tx + L1CoordinatorTxs []common.L1Tx + L2Txs []common.L2Tx + CreatedAccounts []common.Account + ExitTree []common.ExitInfo + Batch *common.Batch +} + +// 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 { + parser := NewParser(strings.NewReader(set)) + parsedSet, err := parser.Parse(false) + require.Nil(tc.t, err) + + tc.Instructions = parsedSet.Instructions + tc.accountsNames = parsedSet.Accounts + tc.TokenIDs = parsedSet.TokenIDs + + tc.generateKeys(tc.accountsNames) + + var blocks []BlockData + currBatchNum := 0 + var currBlock BlockData + var currBatch BatchData + idx := 256 + for _, inst := range parsedSet.Instructions { + switch inst.Type { + case common.TxTypeCreateAccountDeposit, common.TxTypeCreateAccountDepositTransfer: + tx := common.L1Tx{ + // TxID + FromEthAddr: tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Addr, + FromBJJ: tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].BJJ.Public(), + TokenID: inst.TokenID, + LoadAmount: big.NewInt(int64(inst.LoadAmount)), + Type: inst.Type, + } + if tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx == common.Idx(0) { // if account.Idx is not set yet, set it and increment idx + tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx = common.Idx(idx) + + tc.l1CreatedAccounts[idxTokenIDToString(inst.From, inst.TokenID)] = tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)] + idx++ + } + if inst.Type == common.TxTypeCreateAccountDepositTransfer { + tx.Amount = big.NewInt(int64(inst.Amount)) + } + currBatch.L1UserTxs = append(currBatch.L1UserTxs, tx) + case common.TxTypeDeposit, common.TxTypeDepositTransfer: + tx := common.L1Tx{ + // TxID + FromIdx: &tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx, + FromEthAddr: tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Addr, + FromBJJ: tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].BJJ.Public(), + TokenID: inst.TokenID, + LoadAmount: big.NewInt(int64(inst.LoadAmount)), + Type: inst.Type, + } + if tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx == common.Idx(0) { + // if account.Idx is not set yet, set it and increment idx + tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx = common.Idx(idx) + + tc.l1CreatedAccounts[idxTokenIDToString(inst.From, inst.TokenID)] = tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)] + idx++ + } + if inst.Type == common.TxTypeDepositTransfer { + tx.Amount = big.NewInt(int64(inst.Amount)) + // if ToIdx is not set yet, set it and increment idx + if tc.accounts[idxTokenIDToString(inst.To, inst.TokenID)].Idx == common.Idx(0) { + tc.accounts[idxTokenIDToString(inst.To, inst.TokenID)].Idx = common.Idx(idx) + + tc.l1CreatedAccounts[idxTokenIDToString(inst.To, inst.TokenID)] = tc.accounts[idxTokenIDToString(inst.To, inst.TokenID)] + tx.ToIdx = common.Idx(idx) + idx++ + } else { + // if Idx account of To already exist, use it for ToIdx + tx.ToIdx = tc.accounts[idxTokenIDToString(inst.To, inst.TokenID)].Idx + } + } + currBatch.L1UserTxs = append(currBatch.L1UserTxs, tx) + case common.TxTypeTransfer: + tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce++ + // if account of receiver does not exist, create a new CoordinatorL1Tx creating the account + if _, ok := tc.l1CreatedAccounts[idxTokenIDToString(inst.To, inst.TokenID)]; !ok { + tx := common.L1Tx{ + FromEthAddr: tc.accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr, + FromBJJ: tc.accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(), + TokenID: inst.TokenID, + LoadAmount: big.NewInt(int64(inst.Amount)), + Type: common.TxTypeCreateAccountDeposit, + } + tc.accounts[idxTokenIDToString(inst.To, inst.TokenID)].Idx = common.Idx(idx) + tc.l1CreatedAccounts[idxTokenIDToString(inst.To, inst.TokenID)] = tc.accounts[idxTokenIDToString(inst.To, inst.TokenID)] + currBatch.L1CoordinatorTxs = append(currBatch.L1CoordinatorTxs, tx) + idx++ + } + toEthAddr := new(ethCommon.Address) + *toEthAddr = tc.accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr + rqToEthAddr := new(ethCommon.Address) + *rqToEthAddr = tc.accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr + tx := common.L2Tx{ + FromIdx: tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx, + ToIdx: tc.accounts[idxTokenIDToString(inst.To, inst.TokenID)].Idx, + Amount: big.NewInt(int64(inst.Amount)), + Fee: common.FeeSelector(inst.Fee), + Nonce: tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce, + BatchNum: common.BatchNum(currBatchNum), + Type: common.TxTypeTransfer, + } + nTx, err := common.NewPoolL2Tx(tx.PoolL2Tx()) + if err != nil { + panic(err) + } + nL2Tx, err := nTx.L2Tx() + if err != nil { + panic(err) + } + tx = *nL2Tx + + currBatch.L2Txs = append(currBatch.L2Txs, tx) + case common.TxTypeExit: + tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce++ + tx := common.L2Tx{ + FromIdx: tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx, + ToIdx: common.Idx(1), // as is an Exit + Amount: big.NewInt(int64(inst.Amount)), + Nonce: tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce, + Type: common.TxTypeExit, + } + nTx, err := common.NewPoolL2Tx(tx.PoolL2Tx()) + if err != nil { + panic(err) + } + nL2Tx, err := nTx.L2Tx() + if err != nil { + panic(err) + } + tx = *nL2Tx + currBatch.L2Txs = append(currBatch.L2Txs, tx) + case common.TxTypeForceExit: + fromIdx := new(common.Idx) + *fromIdx = tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx + tx := common.L1Tx{ + FromIdx: fromIdx, + ToIdx: common.Idx(1), // as is an Exit + TokenID: inst.TokenID, + Amount: big.NewInt(int64(inst.Amount)), + Type: common.TxTypeExit, + } + currBatch.L1UserTxs = append(currBatch.L1UserTxs, tx) + case TypeNewBatch: + currBlock.Batches = append(currBlock.Batches, currBatch) + currBatchNum++ + currBatch = BatchData{} + case TypeNewBlock: + currBlock.Batches = append(currBlock.Batches, currBatch) + currBatchNum++ + currBatch = BatchData{} + blocks = append(blocks, currBlock) + currBlock = BlockData{} + default: + log.Fatalf("Unexpected type: %s", inst.Type) + } + } + currBlock.Batches = append(currBlock.Batches, currBatch) + blocks = append(blocks, currBlock) + + return blocks +} // 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 { parser := NewParser(strings.NewReader(set)) - parsedSet, err := parser.Parse() + parsedSet, err := parser.Parse(true) require.Nil(tc.t, err) tc.Instructions = parsedSet.Instructions @@ -122,8 +301,7 @@ func (tc *TestContext) GeneratePoolL2Txs(set string) []common.PoolL2Tx { } txs = append(txs, tx) default: - log.Warnf("instruction type unrecognized: %s", inst.Type) - continue + log.Fatalf("instruction type unrecognized: %s", inst.Type) } } @@ -160,138 +338,3 @@ func (tc *TestContext) generateKeys(accNames []string) map[string]*Account { } return acc } - -/* -// GenerateTestTxs generates L1Tx & PoolL2Tx in a deterministic way for the -// given ParsedSet. -func GenerateTestTxs(t *testing.T, parsedSet *ParsedSet) ([][]common.L1Tx, [][]common.L1Tx, [][]common.PoolL2Tx, []common.Token) { - accounts := generateKeys(t, parsedSet.Accounts) - l1CreatedAccounts := make(map[string]*Account) - - var batchL1Txs []common.L1Tx - var batchCoordinatorL1Txs []common.L1Tx - var batchPoolL2Txs []common.PoolL2Tx - var l1Txs [][]common.L1Tx - var coordinatorL1Txs [][]common.L1Tx - var poolL2Txs [][]common.PoolL2Tx - idx := 256 - for _, inst := range parsedSet.Instructions { - switch inst.Type { - case common.TxTypeCreateAccountDeposit: - tx := common.L1Tx{ - // TxID - FromEthAddr: accounts[idxTokenIDToString(inst.From, inst.TokenID)].Addr, - FromBJJ: accounts[idxTokenIDToString(inst.From, inst.TokenID)].BJJ.Public(), - TokenID: inst.TokenID, - Amount: big.NewInt(0), - LoadAmount: big.NewInt(int64(inst.Amount)), - Type: common.TxTypeCreateAccountDeposit, - } - batchL1Txs = append(batchL1Txs, tx) - if accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx == common.Idx(0) { // if account.Idx is not set yet, set it and increment idx - accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx = common.Idx(idx) - - l1CreatedAccounts[idxTokenIDToString(inst.From, inst.TokenID)] = accounts[idxTokenIDToString(inst.From, inst.TokenID)] - idx++ - } - case common.TxTypeTransfer: - // if account of receiver does not exist, create a new CoordinatorL1Tx creating the account - if _, ok := l1CreatedAccounts[idxTokenIDToString(inst.To, inst.TokenID)]; !ok { - tx := common.L1Tx{ - FromEthAddr: accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr, - FromBJJ: accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(), - TokenID: inst.TokenID, - LoadAmount: big.NewInt(int64(inst.Amount)), - Type: common.TxTypeCreateAccountDeposit, - } - accounts[idxTokenIDToString(inst.To, inst.TokenID)].Idx = common.Idx(idx) - l1CreatedAccounts[idxTokenIDToString(inst.To, inst.TokenID)] = accounts[idxTokenIDToString(inst.To, inst.TokenID)] - batchCoordinatorL1Txs = append(batchCoordinatorL1Txs, tx) - idx++ - } - tx := common.PoolL2Tx{ - FromIdx: accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx, - ToIdx: accounts[idxTokenIDToString(inst.To, inst.TokenID)].Idx, - ToEthAddr: accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr, - ToBJJ: accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(), - TokenID: inst.TokenID, - Amount: big.NewInt(int64(inst.Amount)), - Fee: common.FeeSelector(inst.Fee), - Nonce: accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce, - State: common.PoolL2TxStatePending, - RqToEthAddr: accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr, - RqToBJJ: accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(), - Type: common.TxTypeTransfer, - } - nTx, err := common.NewPoolL2Tx(&tx) - if err != nil { - panic(err) - } - tx = *nTx - // perform signature and set it to tx.Signature - toSign, err := tx.HashToSign() - if err != nil { - panic(err) - } - sig := accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.SignPoseidon(toSign) - tx.Signature = sig - - accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce++ - batchPoolL2Txs = append(batchPoolL2Txs, tx) - - case common.TxTypeExit, common.TxTypeForceExit: - tx := common.L1Tx{ - FromIdx: accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx, - ToIdx: common.Idx(1), // as is an Exit - TokenID: inst.TokenID, - Amount: big.NewInt(int64(inst.Amount)), - Type: common.TxTypeExit, - } - batchL1Txs = append(batchL1Txs, tx) - case TypeNewBatch: - l1Txs = append(l1Txs, batchL1Txs) - coordinatorL1Txs = append(coordinatorL1Txs, batchCoordinatorL1Txs) - poolL2Txs = append(poolL2Txs, batchPoolL2Txs) - batchL1Txs = []common.L1Tx{} - batchCoordinatorL1Txs = []common.L1Tx{} - batchPoolL2Txs = []common.PoolL2Tx{} - default: - continue - } - } - l1Txs = append(l1Txs, batchL1Txs) - coordinatorL1Txs = append(coordinatorL1Txs, batchCoordinatorL1Txs) - poolL2Txs = append(poolL2Txs, batchPoolL2Txs) - tokens := []common.Token{} - for i := 0; i < len(poolL2Txs); i++ { - for j := 0; j < len(poolL2Txs[i]); j++ { - id := poolL2Txs[i][j].TokenID - found := false - for k := 0; k < len(tokens); k++ { - if tokens[k].TokenID == id { - found = true - break - } - } - if !found { - tokens = append(tokens, common.Token{ - TokenID: id, - EthBlockNum: 1, - EthAddr: ethCommon.BigToAddress(big.NewInt(int64(i*10000 + j))), - }) - } - } - } - return l1Txs, coordinatorL1Txs, poolL2Txs, tokens -} - -// GenerateTestTxsFromSet reurns the L1 & L2 transactions for a given Set of -// Instructions code -func GenerateTestTxsFromSet(t *testing.T, set string) ([][]common.L1Tx, [][]common.L1Tx, [][]common.PoolL2Tx, []common.Token) { - parser := NewParser(strings.NewReader(set)) - parsedSet, err := parser.Parse() - require.Nil(t, err) - - return GenerateTestTxs(t, parsedSet) -} -*/ diff --git a/test/txs_test.go b/test/txs_test.go index 5b04c02..b6e376d 100644 --- a/test/txs_test.go +++ b/test/txs_test.go @@ -1,23 +1,141 @@ package test import ( + "math/big" "testing" "github.com/hermeznetwork/hermez-node/common" "github.com/stretchr/testify/assert" ) -func TestGeneratePoolL2Txs(t *testing.T) { +func TestGenerateBlocks(t *testing.T) { set := ` + Deposit(1) A: 10 + Deposit(2) A: 20 + Deposit(1) B: 5 + CreateAccountDeposit(1) C: 5 + CreateAccountDepositTransfer(1) D-A: 15, 10 (3) + Transfer(1) A-B: 6 (1) - Transfer(1) B-C: 3 (1) - Transfer(1) C-A: 3 (1) - Transfer(1) A-B: 1 (1) + Transfer(1) B-D: 3 (1) + Transfer(1) A-D: 1 (1) + + // set new batch + > batch + + DepositTransfer(1) A-B: 15, 10 (1) + Transfer(1) C-A : 3 (1) Transfer(2) A-B: 15 (1) + + Deposit(1) User0: 20 + Deposit(3) User1: 20 Transfer(1) User0-User1: 15 (1) Transfer(3) User1-User0: 15 (1) - Transfer(2) B-D: 3 (1) - Exit(1) A: 3 + Transfer(1) A-C: 1 (1) + + > batch + + Transfer(1) User1-User0: 1 (1) + + > block + + // Exits + Transfer(1) A-B: 1 (1) + Exit(1) A: 5 + ` + tc := NewTestContext(t) + blocks := tc.GenerateBlocks(set) + assert.Equal(t, 2, len(blocks)) + assert.Equal(t, 3, len(blocks[0].Batches)) + assert.Equal(t, 1, len(blocks[1].Batches)) + assert.Equal(t, 5, len(blocks[0].Batches[0].L1UserTxs)) + assert.Equal(t, 0, len(blocks[1].Batches[0].L1UserTxs)) + + // Check expected values generated by each line + // #0: Deposit(1) A: 10 + tc.checkL1TxParams(t, blocks[0].Batches[0].L1UserTxs[0], common.TxTypeDeposit, "A1", "", big.NewInt(10), nil) + // #1: Deposit(2) A: 20 + tc.checkL1TxParams(t, blocks[0].Batches[0].L1UserTxs[1], common.TxTypeDeposit, "A2", "", big.NewInt(20), nil) + // #2: Deposit(1) A: 20 + tc.checkL1TxParams(t, blocks[0].Batches[0].L1UserTxs[2], common.TxTypeDeposit, "B1", "", big.NewInt(5), nil) + // #3: CreateAccountDeposit(1) C: 5 + tc.checkL1TxParams(t, blocks[0].Batches[0].L1UserTxs[3], common.TxTypeCreateAccountDeposit, "C1", "", big.NewInt(5), nil) + // #4: CreateAccountDepositTransfer(1) D-A: 15, 10 (3) + tc.checkL1TxParams(t, blocks[0].Batches[0].L1UserTxs[4], common.TxTypeCreateAccountDepositTransfer, "D1", "A1", big.NewInt(15), big.NewInt(10)) + // #5: Transfer(1) A-B: 6 (1) + tc.checkL2TxParams(t, blocks[0].Batches[0].L2Txs[0], common.TxTypeTransfer, "A1", "B1", big.NewInt(6), common.BatchNum(0), common.Nonce(1)) + // #6: Transfer(1) B-D: 3 (1) + tc.checkL2TxParams(t, blocks[0].Batches[0].L2Txs[1], common.TxTypeTransfer, "B1", "D1", big.NewInt(3), common.BatchNum(0), common.Nonce(1)) + // #7: Transfer(1) A-D: 1 (1) + tc.checkL2TxParams(t, blocks[0].Batches[0].L2Txs[2], common.TxTypeTransfer, "A1", "D1", big.NewInt(1), common.BatchNum(0), common.Nonce(2)) + // change of Batch + // #8: DepositTransfer(1) A-B: 15, 10 (1) + tc.checkL1TxParams(t, blocks[0].Batches[1].L1UserTxs[0], common.TxTypeDepositTransfer, "A1", "B1", big.NewInt(15), big.NewInt(10)) + // #9: Deposit(1) User0: 20 + tc.checkL1TxParams(t, blocks[0].Batches[1].L1UserTxs[0], common.TxTypeDepositTransfer, "A1", "B1", big.NewInt(15), big.NewInt(10)) + // #10: Transfer(1) C-A : 3 (1) + tc.checkL2TxParams(t, blocks[0].Batches[1].L2Txs[0], common.TxTypeTransfer, "C1", "A1", big.NewInt(3), common.BatchNum(1), common.Nonce(1)) + // #11: Transfer(2) A-B: 15 (1) + tc.checkL2TxParams(t, blocks[0].Batches[1].L2Txs[1], common.TxTypeTransfer, "A2", "B2", big.NewInt(15), common.BatchNum(1), common.Nonce(1)) + // #12: Deposit(1) User0: 20 + tc.checkL1TxParams(t, blocks[0].Batches[1].L1UserTxs[1], common.TxTypeDeposit, "User01", "", big.NewInt(20), nil) + // #13: Deposit(3) User1: 20 + tc.checkL1TxParams(t, blocks[0].Batches[1].L1UserTxs[2], common.TxTypeDeposit, "User13", "", big.NewInt(20), nil) + // #14: Transfer(1) User0-User1: 15 (1) + tc.checkL2TxParams(t, blocks[0].Batches[1].L2Txs[2], common.TxTypeTransfer, "User01", "User11", big.NewInt(15), common.BatchNum(1), common.Nonce(1)) + // #15: Transfer(3) User1-User0: 15 (1) + tc.checkL2TxParams(t, blocks[0].Batches[1].L2Txs[3], common.TxTypeTransfer, "User13", "User03", big.NewInt(15), common.BatchNum(1), common.Nonce(1)) + // #16: Transfer(1) A-C: 1 (1) + tc.checkL2TxParams(t, blocks[0].Batches[1].L2Txs[4], common.TxTypeTransfer, "A1", "C1", big.NewInt(1), common.BatchNum(1), common.Nonce(3)) + // change of Batch + // #17: Transfer(1) User1-User0: 1 (1) + tc.checkL2TxParams(t, blocks[0].Batches[2].L2Txs[0], common.TxTypeTransfer, "User11", "User01", big.NewInt(1), common.BatchNum(2), common.Nonce(1)) + // change of Block (implies also a change of batch) + // #18: Transfer(1) A-B: 1 (1) + tc.checkL2TxParams(t, blocks[1].Batches[0].L2Txs[0], common.TxTypeTransfer, "A1", "B1", big.NewInt(1), common.BatchNum(3), common.Nonce(4)) +} + +func (tc *TestContext) checkL1TxParams(t *testing.T, tx common.L1Tx, typ common.TxType, from, to string, loadAmount, amount *big.Int) { + assert.Equal(t, typ, tx.Type) + if tx.FromIdx != nil { + assert.Equal(t, tc.accounts[from].Idx, *tx.FromIdx) + } + assert.Equal(t, tc.accounts[from].Addr.Hex(), tx.FromEthAddr.Hex()) + assert.Equal(t, tc.accounts[from].BJJ.Public(), tx.FromBJJ) + if tx.ToIdx != common.Idx(0) { + assert.Equal(t, tc.accounts[to].Idx, tx.ToIdx) + } + if loadAmount != nil { + assert.Equal(t, loadAmount, tx.LoadAmount) + } + if amount != nil { + assert.Equal(t, amount, tx.Amount) + } +} +func (tc *TestContext) checkL2TxParams(t *testing.T, tx common.L2Tx, typ common.TxType, from, to string, amount *big.Int, batchNum common.BatchNum, nonce common.Nonce) { + assert.Equal(t, typ, tx.Type) + assert.Equal(t, tc.accounts[from].Idx, tx.FromIdx) + if tx.Type != common.TxTypeExit { + assert.Equal(t, tc.accounts[to].Idx, tx.ToIdx) + } + if amount != nil { + assert.Equal(t, amount, tx.Amount) + } + assert.Equal(t, batchNum, tx.BatchNum) + assert.Equal(t, nonce, tx.Nonce) +} + +func TestGeneratePoolL2Txs(t *testing.T) { + set := ` + PoolTransfer(1) A-B: 6 (1) + PoolTransfer(1) B-C: 3 (1) + PoolTransfer(1) C-A: 3 (1) + PoolTransfer(1) A-B: 1 (1) + PoolTransfer(2) A-B: 15 (1) + PoolTransfer(1) User0-User1: 15 (1) + PoolTransfer(3) User1-User0: 15 (1) + PoolTransfer(2) B-D: 3 (1) + PoolExit(1) A: 3 ` tc := NewTestContext(t) poolL2Txs := tc.GeneratePoolL2Txs(set) @@ -35,9 +153,9 @@ func TestGeneratePoolL2Txs(t *testing.T) { // load another set in the same TestContext set = ` - Transfer(1) A-B: 6 (1) - Transfer(1) B-C: 3 (1) - Transfer(1) A-C: 3 (1) + PoolTransfer(1) A-B: 6 (1) + PoolTransfer(1) B-C: 3 (1) + PoolTransfer(1) A-C: 3 (1) ` poolL2Txs = tc.GeneratePoolL2Txs(set) assert.Equal(t, common.Nonce(4), poolL2Txs[0].Nonce) diff --git a/test/utils.go b/test/utils.go new file mode 100644 index 0000000..25678fc --- /dev/null +++ b/test/utils.go @@ -0,0 +1,12 @@ +package test + +import "github.com/hermeznetwork/hermez-node/common" + +func extendTokenIDs(o, n []common.TokenID) []common.TokenID { + + return o +} +func extendAccounts(o, n map[string]*Account) map[string]*Account { + + return o +}