arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/test/txs.go
test/txs.goRaw
  1package test
  2
  3import (
  4	"crypto/ecdsa"
  5	"math/big"
  6	"strconv"
  7	"testing"
  8	"time"
  9
 10	ethCommon "github.com/ethereum/go-ethereum/common"
 11	ethCrypto "github.com/ethereum/go-ethereum/crypto"
 12	"github.com/hermeznetwork/hermez-node/common"
 13	"github.com/iden3/go-iden3-crypto/babyjub"
 14)
 15
 16type Account struct {
 17	BJJ   *babyjub.PrivateKey
 18	Addr  ethCommon.Address
 19	Idx   common.Idx
 20	Nonce common.Nonce
 21}
 22
 23// GenerateKeys generates BabyJubJub & Address keys for the given list of
 24// account names in a deterministic way. This means, that for the same given
 25// 'accNames' the keys will be always the same.
 26func GenerateKeys(t *testing.T, accNames []string) map[string]*Account {
 27	acc := make(map[string]*Account)
 28	for i := 1; i < len(accNames)+1; i++ {
 29		// babyjubjub key
 30		var sk babyjub.PrivateKey
 31		copy(sk[:], []byte(strconv.Itoa(i))) // only for testing
 32
 33		// eth address
 34		var key ecdsa.PrivateKey
 35		key.D = big.NewInt(int64(i)) // only for testing
 36		key.PublicKey.X, key.PublicKey.Y = ethCrypto.S256().ScalarBaseMult(key.D.Bytes())
 37		key.Curve = ethCrypto.S256()
 38		addr := ethCrypto.PubkeyToAddress(key.PublicKey)
 39
 40		a := Account{
 41			BJJ:   &sk,
 42			Addr:  addr,
 43			Nonce: 0,
 44		}
 45		acc[accNames[i-1]] = &a
 46	}
 47	return acc
 48}
 49
 50// GenerateTestTxs generates L1Tx & PoolL2Tx in a deterministic way for the
 51// given Instructions.
 52func GenerateTestTxs(t *testing.T, instructions Instructions) ([][]*common.L1Tx, [][]*common.L1Tx, [][]*common.PoolL2Tx) {
 53	accounts := GenerateKeys(t, instructions.Accounts)
 54	l1CreatedAccounts := make(map[string]*Account)
 55
 56	var batchL1txs []*common.L1Tx
 57	var batchCoordinatorL1txs []*common.L1Tx
 58	var batchL2txs []*common.PoolL2Tx
 59	var l1txs [][]*common.L1Tx
 60	var coordinatorL1txs [][]*common.L1Tx
 61	var l2txs [][]*common.PoolL2Tx
 62	idx := 1
 63	for _, inst := range instructions.Instructions {
 64		switch inst.Type {
 65		case common.TxTypeCreateAccountDeposit:
 66			tx := common.L1Tx{
 67				// TxID
 68				FromEthAddr: accounts[idxTokenIDToString(inst.From, inst.TokenID)].Addr,
 69				FromBJJ:     accounts[idxTokenIDToString(inst.From, inst.TokenID)].BJJ.Public(),
 70				TokenID:     inst.TokenID,
 71				LoadAmount:  big.NewInt(int64(inst.Amount)),
 72				Type:        common.TxTypeCreateAccountDeposit,
 73			}
 74			batchL1txs = append(batchL1txs, &tx)
 75			if accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx == common.Idx(0) { // if account.Idx is not set yet, set it and increment idx
 76				accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx = common.Idx(idx)
 77
 78				l1CreatedAccounts[idxTokenIDToString(inst.From, inst.TokenID)] = accounts[idxTokenIDToString(inst.From, inst.TokenID)]
 79				idx++
 80			}
 81		case common.TxTypeTransfer:
 82			// if account of receiver does not exist, create a new CoordinatorL1Tx creating the account
 83			if _, ok := l1CreatedAccounts[idxTokenIDToString(inst.To, inst.TokenID)]; !ok {
 84				tx := common.L1Tx{
 85					FromEthAddr: accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr,
 86					FromBJJ:     accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(),
 87					TokenID:     inst.TokenID,
 88					LoadAmount:  big.NewInt(int64(inst.Amount)),
 89					Type:        common.TxTypeCreateAccountDeposit,
 90				}
 91				accounts[idxTokenIDToString(inst.To, inst.TokenID)].Idx = common.Idx(idx)
 92				l1CreatedAccounts[idxTokenIDToString(inst.To, inst.TokenID)] = accounts[idxTokenIDToString(inst.To, inst.TokenID)]
 93				batchCoordinatorL1txs = append(batchCoordinatorL1txs, &tx)
 94				idx++
 95			}
 96
 97			tx := common.PoolL2Tx{
 98				// TxID: nil,
 99				FromIdx:     accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx,
100				ToIdx:       accounts[idxTokenIDToString(inst.To, inst.TokenID)].Idx,
101				ToEthAddr:   accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr,
102				ToBJJ:       accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(),
103				TokenID:     inst.TokenID,
104				Amount:      big.NewInt(int64(inst.Amount)),
105				Fee:         common.FeeSelector(inst.Fee),
106				Nonce:       accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce,
107				State:       common.PoolL2TxStatePending,
108				Timestamp:   time.Now(),
109				BatchNum:    0,
110				RqToEthAddr: accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr,
111				RqToBJJ:     accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(),
112				Type:        common.TxTypeTransfer,
113			}
114			// perform signature and set it to tx.Signature
115			toSign, err := tx.HashToSign()
116			if err != nil {
117				panic(err)
118			}
119			sig := accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.SignPoseidon(toSign)
120			tx.Signature = sig
121
122			accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce++
123			batchL2txs = append(batchL2txs, &tx)
124
125		case common.TxTypeExit, common.TxTypeForceExit:
126			tx := common.L1Tx{
127				FromIdx: accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx,
128				ToIdx:   common.Idx(1), // as is an Exit
129				TokenID: inst.TokenID,
130				Amount:  big.NewInt(int64(inst.Amount)),
131				Type:    common.TxTypeExit,
132			}
133			batchL1txs = append(batchL1txs, &tx)
134		case TypeNewBatch:
135			l1txs = append(l1txs, batchL1txs)
136			coordinatorL1txs = append(coordinatorL1txs, batchCoordinatorL1txs)
137			l2txs = append(l2txs, batchL2txs)
138			batchL1txs = []*common.L1Tx{}
139			batchCoordinatorL1txs = []*common.L1Tx{}
140			batchL2txs = []*common.PoolL2Tx{}
141		default:
142			continue
143		}
144
145	}
146	l1txs = append(l1txs, batchL1txs)
147	coordinatorL1txs = append(coordinatorL1txs, batchCoordinatorL1txs)
148	l2txs = append(l2txs, batchL2txs)
149
150	return l1txs, coordinatorL1txs, l2txs
151}