From 182e3d36f5d71b97f8d1fae463332c1710426920 Mon Sep 17 00:00:00 2001 From: arnaucube Date: Wed, 7 Oct 2020 16:20:29 +0200 Subject: [PATCH] Add GeneratePoolL2Txs for a parsed set --- test/lang.go | 14 ++--- test/txs.go | 134 +++++++++++++++++++++++++++++++++++++++++++---- test/txs_test.go | 79 ++++++++++++---------------- 3 files changed, 164 insertions(+), 63 deletions(-) diff --git a/test/lang.go b/test/lang.go index f4e5eb9..fc06653 100644 --- a/test/lang.go +++ b/test/lang.go @@ -45,9 +45,9 @@ type Instruction struct { Type common.TxType // D: Deposit, T: Transfer, E: ForceExit } -// Instructions contains the full Set of Instructions representing a full code -type Instructions struct { - Instructions []*Instruction +// ParsedSet contains the full Set of Instructions representing a full code +type ParsedSet struct { + Instructions []Instruction Accounts []string TokenIDs []common.TokenID } @@ -389,8 +389,8 @@ func idxTokenIDToString(idx string, tid common.TokenID) string { } // Parse parses through reader -func (p *Parser) Parse() (Instructions, error) { - var instructions Instructions +func (p *Parser) Parse() (*ParsedSet, error) { + instructions := &ParsedSet{} i := 0 accounts := make(map[string]bool) tokenids := make(map[common.TokenID]bool) @@ -405,13 +405,13 @@ func (p *Parser) Parse() (Instructions, error) { } if err == newEvent { i++ - instructions.Instructions = append(instructions.Instructions, instruction) + instructions.Instructions = append(instructions.Instructions, *instruction) continue } if err != nil { return instructions, fmt.Errorf("error parsing line %d: %s, err: %s", i, instruction.Literal, err.Error()) } - instructions.Instructions = append(instructions.Instructions, instruction) + instructions.Instructions = append(instructions.Instructions, *instruction) accounts[idxTokenIDToString(instruction.From, instruction.TokenID)] = true if instruction.Type == common.TxTypeTransfer { // type: Transfer accounts[idxTokenIDToString(instruction.To, instruction.TokenID)] = true diff --git a/test/txs.go b/test/txs.go index 788722f..d9b5f42 100644 --- a/test/txs.go +++ b/test/txs.go @@ -6,14 +6,33 @@ import ( "strconv" "strings" "testing" + "time" ethCommon "github.com/ethereum/go-ethereum/common" ethCrypto "github.com/ethereum/go-ethereum/crypto" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/log" "github.com/iden3/go-iden3-crypto/babyjub" "github.com/stretchr/testify/require" ) +type TestContext struct { + t *testing.T + Instructions []Instruction + accountsNames []string + accounts map[string]*Account + TokenIDs []common.TokenID + l1CreatedAccounts map[string]*Account +} + +func NewTestContext(t *testing.T) *TestContext { + return &TestContext{ + t: t, + accounts: make(map[string]*Account), + l1CreatedAccounts: make(map[string]*Account), + } +} + // Account contains the data related to a testing account type Account struct { BJJ *babyjub.PrivateKey @@ -22,12 +41,105 @@ type Account struct { Nonce common.Nonce } -// GenerateKeys generates BabyJubJub & Address keys for the given list of +// func (tc *TestContext) GenerateBlocks() []BlockData { +// +// return nil +// } + +// GeneratePoolL2Txs returns an array of common.PoolL2Tx from a given set. It +// uses the accounts (keys & nonces) of the TestContext. +func (tc *TestContext) GeneratePoolL2Txs(set string) []common.PoolL2Tx { + parser := NewParser(strings.NewReader(set)) + parsedSet, err := parser.Parse() + require.Nil(tc.t, err) + + tc.Instructions = parsedSet.Instructions + tc.accountsNames = parsedSet.Accounts + tc.TokenIDs = parsedSet.TokenIDs + + tc.generateKeys(tc.accountsNames) + + txs := []common.PoolL2Tx{} + for _, inst := range tc.Instructions { + switch inst.Type { + case common.TxTypeTransfer: + tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce++ + // if account of receiver does not exist, don't use + // ToIdx, and use only ToEthAddr & ToBJJ + toIdx := new(common.Idx) + if _, ok := tc.l1CreatedAccounts[idxTokenIDToString(inst.To, inst.TokenID)]; !ok { + *toIdx = 0 + } else { + *toIdx = tc.accounts[idxTokenIDToString(inst.To, inst.TokenID)].Idx + } + // TODO once common.L{x}Txs parameter pointers is undone, update this lines related to pointers usage + 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.PoolL2Tx{ + FromIdx: tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx, + ToIdx: toIdx, + ToEthAddr: toEthAddr, + ToBJJ: tc.accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(), + TokenID: inst.TokenID, + Amount: big.NewInt(int64(inst.Amount)), + Fee: common.FeeSelector(inst.Fee), + Nonce: tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce, + State: common.PoolL2TxStatePending, + Timestamp: time.Now(), + BatchNum: nil, + RqToEthAddr: rqToEthAddr, + RqToBJJ: tc.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 := tc.accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.SignPoseidon(toSign) + tx.Signature = sig + + txs = append(txs, tx) + case common.TxTypeExit: + tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce++ + // TODO once common.L{x}Txs parameter pointers is undone, update this lines related to pointers usage + toIdx := new(common.Idx) + *toIdx = common.Idx(1) // as is an Exit + tx := common.PoolL2Tx{ + FromIdx: tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx, + ToIdx: toIdx, // as is an Exit + TokenID: inst.TokenID, + Amount: big.NewInt(int64(inst.Amount)), + Nonce: tc.accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce, + Type: common.TxTypeExit, + } + txs = append(txs, tx) + default: + log.Warnf("instruction type unrecognized: %s", inst.Type) + continue + } + } + + return txs +} + +// generateKeys generates BabyJubJub & Address keys for the given list of // account names in a deterministic way. This means, that for the same given -// 'accNames' the keys will be always the same. -func GenerateKeys(t *testing.T, accNames []string) map[string]*Account { +// 'accNames' in a certain order, the keys will be always the same. +func (tc *TestContext) generateKeys(accNames []string) map[string]*Account { acc := make(map[string]*Account) for i := 1; i < len(accNames)+1; i++ { + if _, ok := tc.accounts[accNames[i-1]]; ok { + // account already created + continue + } // babyjubjub key var sk babyjub.PrivateKey copy(sk[:], []byte(strconv.Itoa(i))) // only for testing @@ -44,15 +156,16 @@ func GenerateKeys(t *testing.T, accNames []string) map[string]*Account { Addr: addr, Nonce: 0, } - acc[accNames[i-1]] = &a + tc.accounts[accNames[i-1]] = &a } return acc } +/* // GenerateTestTxs generates L1Tx & PoolL2Tx in a deterministic way for the -// given Instructions. -func GenerateTestTxs(t *testing.T, instructions Instructions) ([][]common.L1Tx, [][]common.L1Tx, [][]common.PoolL2Tx, []common.Token) { - accounts := GenerateKeys(t, instructions.Accounts) +// 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 @@ -62,7 +175,7 @@ func GenerateTestTxs(t *testing.T, instructions Instructions) ([][]common.L1Tx, var coordinatorL1Txs [][]common.L1Tx var poolL2Txs [][]common.PoolL2Tx idx := 256 - for _, inst := range instructions.Instructions { + for _, inst := range parsedSet.Instructions { switch inst.Type { case common.TxTypeCreateAccountDeposit: tx := common.L1Tx{ @@ -176,8 +289,9 @@ func GenerateTestTxs(t *testing.T, instructions Instructions) ([][]common.L1Tx, // Instructions code func GenerateTestTxsFromSet(t *testing.T, set string) ([][]common.L1Tx, [][]common.L1Tx, [][]common.PoolL2Tx, []common.Token) { parser := NewParser(strings.NewReader(set)) - instructions, err := parser.Parse() + parsedSet, err := parser.Parse() require.Nil(t, err) - return GenerateTestTxs(t, instructions) + return GenerateTestTxs(t, parsedSet) } +*/ diff --git a/test/txs_test.go b/test/txs_test.go index 57573b9..5b04c02 100644 --- a/test/txs_test.go +++ b/test/txs_test.go @@ -1,59 +1,46 @@ package test import ( - "strings" "testing" "github.com/hermeznetwork/hermez-node/common" "github.com/stretchr/testify/assert" ) -func TestGenerateTestL2Txs(t *testing.T) { - s := ` - A (1): 10 - A (2): 20 - B (1): 5 - A-B (1): 6 1 - B-C (1): 3 1 - > advance batch - C-A (1): 3 1 - A-B (1): 1 1 - A-B (2): 15 1 - User0 (1): 20 - User1 (3) : 20 - User0-User1 (1): 15 1 - User1-User0 (3): 15 1 - B-D (2): 3 1 +func TestGeneratePoolL2Txs(t *testing.T) { + set := ` + 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(2) A-B: 15 (1) + Transfer(1) User0-User1: 15 (1) + Transfer(3) User1-User0: 15 (1) + Transfer(2) B-D: 3 (1) + Exit(1) A: 3 ` - parser := NewParser(strings.NewReader(s)) - instructions, err := parser.Parse() - assert.Nil(t, err) + tc := NewTestContext(t) + poolL2Txs := tc.GeneratePoolL2Txs(set) + assert.Equal(t, 9, len(poolL2Txs)) + assert.Equal(t, common.TxTypeTransfer, poolL2Txs[0].Type) + assert.Equal(t, common.TxTypeExit, poolL2Txs[8].Type) + assert.Equal(t, tc.accounts["B1"].Addr.Hex(), poolL2Txs[0].ToEthAddr.Hex()) + assert.Equal(t, tc.accounts["B1"].BJJ.Public().String(), poolL2Txs[0].ToBJJ.String()) + assert.Equal(t, tc.accounts["User11"].Addr.Hex(), poolL2Txs[5].ToEthAddr.Hex()) + assert.Equal(t, tc.accounts["User11"].BJJ.Public().String(), poolL2Txs[5].ToBJJ.String()) - l1txs, coordinatorL1txs, l2txs, _ := GenerateTestTxs(t, instructions) - assert.Equal(t, 2, len(l1txs)) - assert.Equal(t, 3, len(l1txs[0])) - assert.Equal(t, 1, len(coordinatorL1txs[0])) - assert.Equal(t, 2, len(l2txs[0])) - assert.Equal(t, 2, len(l1txs[1])) - assert.Equal(t, 4, len(coordinatorL1txs[1])) - assert.Equal(t, 6, len(l2txs[1])) + assert.Equal(t, common.Nonce(1), poolL2Txs[0].Nonce) + assert.Equal(t, common.Nonce(2), poolL2Txs[3].Nonce) + assert.Equal(t, common.Nonce(3), poolL2Txs[8].Nonce) - accounts := GenerateKeys(t, instructions.Accounts) - - // l1txs - assert.Equal(t, common.TxTypeCreateAccountDeposit, l1txs[0][0].Type) - assert.Equal(t, accounts["A1"].BJJ.Public().String(), l1txs[0][0].FromBJJ.String()) - assert.Equal(t, accounts["A2"].BJJ.Public().String(), l1txs[0][1].FromBJJ.String()) - assert.Equal(t, accounts["B1"].BJJ.Public().String(), l1txs[0][2].FromBJJ.String()) - assert.Equal(t, accounts["User13"].BJJ.Public().String(), l1txs[1][1].FromBJJ.String()) - - // l2txs - assert.Equal(t, common.TxTypeTransfer, l2txs[0][0].Type) - assert.Equal(t, common.Idx(256), l2txs[0][0].FromIdx) - assert.Equal(t, common.Idx(258), l2txs[0][0].ToIdx) - assert.Equal(t, accounts["B1"].BJJ.Public().String(), l2txs[0][0].ToBJJ.String()) - assert.Equal(t, accounts["B1"].Addr.Hex(), l2txs[0][0].ToEthAddr.Hex()) - assert.Equal(t, common.Nonce(0), l2txs[0][0].Nonce) - assert.Equal(t, common.Nonce(1), l2txs[1][1].Nonce) - assert.Equal(t, common.FeeSelector(1), l2txs[0][0].Fee) + // 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) + ` + poolL2Txs = tc.GeneratePoolL2Txs(set) + assert.Equal(t, common.Nonce(4), poolL2Txs[0].Nonce) + assert.Equal(t, common.Nonce(2), poolL2Txs[1].Nonce) + assert.Equal(t, common.Nonce(5), poolL2Txs[2].Nonce) }