arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/common/l1tx.go
common/l1tx.goRaw
  1package common
  2
  3import (
  4	"math/big"
  5
  6	ethCommon "github.com/ethereum/go-ethereum/common"
  7	"github.com/iden3/go-iden3-crypto/babyjub"
  8)
  9
 10const (
 11	fromBJJCompressedB = 256
 12	fromEthAddrB       = 160
 13	f16B               = 16
 14	tokenIDB           = 32
 15	cidXB              = 32
 16)
 17
 18// L1Tx is a struct that represents a L1 tx
 19type L1Tx struct {
 20	// Stored in DB: mandatory fileds
 21	TxID            TxID
 22	ToForgeL1TxsNum uint32 // toForgeL1TxsNum in which the tx was forged / will be forged
 23	Position        int
 24	UserOrigin      bool // true if the tx was originated by a user, false if it was aoriginated by a coordinator. Note that this differ from the spec for implementation simplification purpposes
 25	FromIdx         Idx  // FromIdx is used by L1Tx/Deposit to indicate the Idx receiver of the L1Tx.LoadAmount (deposit)
 26	FromEthAddr     ethCommon.Address
 27	FromBJJ         *babyjub.PublicKey
 28	ToIdx           Idx // ToIdx is ignored in L1Tx/Deposit, but used in the L1Tx/DepositAndTransfer
 29	TokenID         TokenID
 30	Amount          *big.Int
 31	LoadAmount      *big.Int
 32	EthBlockNum     int64 // Ethereum Block Number in which this L1Tx was added to the queue
 33	Type            TxType
 34	BatchNum        BatchNum
 35}
 36
 37// Tx returns a *Tx from the L1Tx
 38func (tx *L1Tx) Tx() *Tx {
 39	f := new(big.Float).SetInt(tx.Amount)
 40	amountFloat, _ := f.Float64()
 41	genericTx := &Tx{
 42		IsL1:            true,
 43		TxID:            tx.TxID,
 44		Type:            tx.Type,
 45		Position:        tx.Position,
 46		FromIdx:         tx.FromIdx,
 47		ToIdx:           tx.ToIdx,
 48		Amount:          tx.Amount,
 49		AmountFloat:     amountFloat,
 50		TokenID:         tx.TokenID,
 51		ToForgeL1TxsNum: tx.ToForgeL1TxsNum,
 52		UserOrigin:      tx.UserOrigin,
 53		FromEthAddr:     tx.FromEthAddr,
 54		FromBJJ:         tx.FromBJJ,
 55		LoadAmount:      tx.LoadAmount,
 56		EthBlockNum:     tx.EthBlockNum,
 57	}
 58	if tx.LoadAmount != nil {
 59		lf := new(big.Float).SetInt(tx.LoadAmount)
 60		loadAmountFloat, _ := lf.Float64()
 61		genericTx.LoadAmountFloat = loadAmountFloat
 62	}
 63	return genericTx
 64}
 65
 66// Bytes encodes a L1Tx into []byte
 67func (tx *L1Tx) Bytes(nLevels int) []byte {
 68	res := big.NewInt(0)
 69	res = res.Add(res, big.NewInt(0).Or(big.NewInt(0), tx.ToIdx.BigInt()))
 70	res = res.Add(res, big.NewInt(0).Lsh(big.NewInt(0).Or(big.NewInt(0), big.NewInt(int64(tx.TokenID))), uint(nLevels)))
 71	res = res.Add(res, big.NewInt(0).Lsh(big.NewInt(0).Or(big.NewInt(0), tx.Amount), uint(nLevels+tokenIDB)))
 72	res = res.Add(res, big.NewInt(0).Lsh(big.NewInt(0).Or(big.NewInt(0), tx.LoadAmount), uint(nLevels+tokenIDB+f16B)))
 73	res = res.Add(res, big.NewInt(0).Lsh(big.NewInt(0).Or(big.NewInt(0), tx.FromIdx.BigInt()), uint(nLevels+tokenIDB+2*f16B)))
 74
 75	fromBJJ := big.NewInt(0)
 76	fromBJJ.SetString(tx.FromBJJ.String(), 16)
 77	fromBJJCompressed := big.NewInt(0).Or(big.NewInt(0), fromBJJ)
 78	res = res.Add(res, big.NewInt(0).Lsh(fromBJJCompressed, uint(2*nLevels+tokenIDB+2*f16B)))
 79
 80	fromEthAddr := big.NewInt(0).Or(big.NewInt(0), tx.FromEthAddr.Hash().Big())
 81	res = res.Add(res, big.NewInt(0).Lsh(fromEthAddr, uint(fromBJJCompressedB+2*nLevels+tokenIDB+2*f16B)))
 82
 83	return res.Bytes()
 84}
 85
 86// L1TxFromBytes decodes a L1Tx from []byte
 87func L1TxFromBytes(l1TxEncoded []byte) (*L1Tx, error) {
 88	l1Tx := &L1Tx{}
 89	var idxB uint = cidXB
 90
 91	l1TxEncodedBI := big.NewInt(0)
 92	l1TxEncodedBI.SetBytes(l1TxEncoded)
 93
 94	toIdx, err := IdxFromBigInt(extract(l1TxEncodedBI, 0, idxB))
 95
 96	if err != nil {
 97		return nil, err
 98	}
 99
100	l1Tx.ToIdx = toIdx
101
102	l1Tx.TokenID = TokenID(extract(l1TxEncodedBI, idxB, tokenIDB).Uint64())
103	l1Tx.Amount = extract(l1TxEncodedBI, idxB+tokenIDB, f16B)
104	l1Tx.LoadAmount = extract(l1TxEncodedBI, idxB+tokenIDB+f16B, f16B)
105	fromIdx, err := IdxFromBigInt(extract(l1TxEncodedBI, idxB+tokenIDB+2*f16B, f16B))
106
107	if err != nil {
108		return nil, err
109	}
110
111	l1Tx.FromIdx = fromIdx
112
113	var pkComp babyjub.PublicKeyComp
114	copy(pkComp[:], extract(l1TxEncodedBI, 2*idxB+tokenIDB+2*f16B, fromBJJCompressedB).Bytes())
115	pk, err := pkComp.Decompress()
116
117	if err != nil {
118		return nil, err
119	}
120
121	l1Tx.FromBJJ = pk
122
123	l1Tx.FromEthAddr = ethCommon.BigToAddress(extract(l1TxEncodedBI, fromBJJCompressedB+2*idxB+tokenIDB+2*f16B, fromEthAddrB))
124
125	return l1Tx, nil
126}
127
128// extract masks and shifts a bigInt
129func extract(num *big.Int, origin uint, len uint) *big.Int {
130	mask := big.NewInt(0).Sub(big.NewInt(0).Lsh(big.NewInt(1), len), big.NewInt(1))
131	return big.NewInt(0).And(big.NewInt(0).Rsh(num, origin), mask)
132}