arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/common/l1tx.go
common/l1tx.goRaw
  1package common
  2
  3import (
  4	"encoding/binary"
  5	"fmt"
  6	"math/big"
  7
  8	ethCommon "github.com/ethereum/go-ethereum/common"
  9	"github.com/iden3/go-iden3-crypto/babyjub"
 10)
 11
 12const (
 13	// L1TxBytesLen is the length of the byte array that represents the L1Tx
 14	L1TxBytesLen = 72
 15)
 16
 17// L1Tx is a struct that represents a L1 tx
 18type L1Tx struct {
 19	// Stored in DB: mandatory fileds
 20
 21	// TxID (12 bytes) for L1Tx is:
 22	// bytes:  |  1   |        8        |    2     |      1      |
 23	// values: | type | ToForgeL1TxsNum | Position | 0 (padding) |
 24	// where type:
 25	// 	- L1UserTx: 0
 26	// 	- L1CoordinatorTx: 1
 27	TxID            TxID
 28	ToForgeL1TxsNum int64 // toForgeL1TxsNum in which the tx was forged / will be forged
 29	Position        int
 30	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
 31	FromIdx         Idx  // FromIdx is used by L1Tx/Deposit to indicate the Idx receiver of the L1Tx.LoadAmount (deposit)
 32	FromEthAddr     ethCommon.Address
 33	FromBJJ         *babyjub.PublicKey
 34	ToIdx           Idx // ToIdx is ignored in L1Tx/Deposit, but used in the L1Tx/DepositAndTransfer
 35	TokenID         TokenID
 36	Amount          *big.Int
 37	LoadAmount      *big.Int
 38	EthBlockNum     int64 // Ethereum Block Number in which this L1Tx was added to the queue
 39	Type            TxType
 40	BatchNum        *BatchNum
 41	USD             *float64
 42	LoadAmountUSD   *float64
 43}
 44
 45// NewL1Tx returns the given L1Tx with the TxId & Type parameters calculated
 46// from the L1Tx values
 47func NewL1Tx(l1Tx *L1Tx) (*L1Tx, error) {
 48	// calculate TxType
 49	var txType TxType
 50	if l1Tx.FromIdx == Idx(0) {
 51		if l1Tx.ToIdx == Idx(0) {
 52			txType = TxTypeCreateAccountDeposit
 53		} else if l1Tx.ToIdx >= IdxUserThreshold {
 54			txType = TxTypeCreateAccountDepositTransfer
 55		} else {
 56			return l1Tx, fmt.Errorf("Can not determine type of L1Tx, invalid ToIdx value: %d", l1Tx.ToIdx)
 57		}
 58	} else if l1Tx.FromIdx >= IdxUserThreshold {
 59		if l1Tx.ToIdx == Idx(0) {
 60			txType = TxTypeDeposit
 61		} else if l1Tx.ToIdx == Idx(1) {
 62			txType = TxTypeExit
 63		} else if l1Tx.ToIdx >= IdxUserThreshold {
 64			if l1Tx.LoadAmount.Int64() == int64(0) {
 65				txType = TxTypeForceTransfer
 66			} else {
 67				txType = TxTypeDepositTransfer
 68			}
 69		} else {
 70			return l1Tx, fmt.Errorf("Can not determine type of L1Tx, invalid ToIdx value: %d", l1Tx.ToIdx)
 71		}
 72	} else {
 73		return l1Tx, fmt.Errorf("Can not determine type of L1Tx, invalid FromIdx value: %d", l1Tx.FromIdx)
 74	}
 75
 76	if l1Tx.Type != "" && l1Tx.Type != txType {
 77		return l1Tx, fmt.Errorf("L1Tx.Type: %s, should be: %s", l1Tx.Type, txType)
 78	}
 79	l1Tx.Type = txType
 80
 81	var txid [TxIDLen]byte
 82	if !l1Tx.UserOrigin {
 83		txid[0] = TxIDPrefixL1CoordTx
 84	}
 85	var toForgeL1TxsNumBytes [8]byte
 86	binary.BigEndian.PutUint64(toForgeL1TxsNumBytes[:], uint64(l1Tx.ToForgeL1TxsNum))
 87	copy(txid[1:9], toForgeL1TxsNumBytes[:])
 88
 89	var positionBytes [2]byte
 90	binary.BigEndian.PutUint16(positionBytes[:], uint16(l1Tx.Position))
 91	copy(txid[9:11], positionBytes[:])
 92	l1Tx.TxID = TxID(txid)
 93
 94	return l1Tx, nil
 95}
 96
 97// Tx returns a *Tx from the L1Tx
 98func (tx *L1Tx) Tx() *Tx {
 99	f := new(big.Float).SetInt(tx.Amount)
100	amountFloat, _ := f.Float64()
101	genericTx := &Tx{
102		IsL1:            true,
103		TxID:            tx.TxID,
104		Type:            tx.Type,
105		Position:        tx.Position,
106		FromIdx:         tx.FromIdx,
107		ToIdx:           tx.ToIdx,
108		Amount:          tx.Amount,
109		AmountFloat:     amountFloat,
110		TokenID:         tx.TokenID,
111		ToForgeL1TxsNum: tx.ToForgeL1TxsNum,
112		UserOrigin:      tx.UserOrigin,
113		FromEthAddr:     tx.FromEthAddr,
114		FromBJJ:         tx.FromBJJ,
115		LoadAmount:      tx.LoadAmount,
116		EthBlockNum:     tx.EthBlockNum,
117		USD:             tx.USD,
118		LoadAmountUSD:   tx.LoadAmountUSD,
119	}
120	if tx.LoadAmount != nil {
121		lf := new(big.Float).SetInt(tx.LoadAmount)
122		loadAmountFloat, _ := lf.Float64()
123		genericTx.LoadAmountFloat = &loadAmountFloat
124	}
125	return genericTx
126}
127
128// Bytes encodes a L1Tx into []byte
129func (tx *L1Tx) Bytes(nLevels int) ([]byte, error) {
130	var b [L1TxBytesLen]byte
131	copy(b[0:20], tx.FromEthAddr.Bytes())
132	pkComp := tx.FromBJJ.Compress()
133	copy(b[20:52], pkComp[:])
134	fromIdxBytes, err := tx.FromIdx.Bytes()
135	if err != nil {
136		return nil, err
137	}
138	copy(b[52:58], fromIdxBytes[:])
139	loadAmountFloat16, err := NewFloat16(tx.LoadAmount)
140	if err != nil {
141		return nil, err
142	}
143	copy(b[58:60], loadAmountFloat16.Bytes())
144	amountFloat16, err := NewFloat16(tx.Amount)
145	if err != nil {
146		return nil, err
147	}
148	copy(b[60:62], amountFloat16.Bytes())
149	copy(b[62:66], tx.TokenID.Bytes())
150	toIdxBytes, err := tx.ToIdx.Bytes()
151	if err != nil {
152		return nil, err
153	}
154	copy(b[66:72], toIdxBytes[:])
155	return b[:], nil
156}
157
158// L1TxFromBytes decodes a L1Tx from []byte
159func L1TxFromBytes(b []byte) (*L1Tx, error) {
160	if len(b) != L1TxBytesLen {
161		return nil, fmt.Errorf("Can not parse L1Tx bytes, expected length %d, current: %d", 68, len(b))
162	}
163
164	tx := &L1Tx{}
165	var err error
166	tx.FromEthAddr = ethCommon.BytesToAddress(b[0:20])
167	pkCompB := b[20:52]
168	var pkComp babyjub.PublicKeyComp
169	copy(pkComp[:], pkCompB)
170	tx.FromBJJ, err = pkComp.Decompress()
171	if err != nil {
172		return nil, err
173	}
174	tx.FromIdx, err = IdxFromBytes(b[52:58])
175	if err != nil {
176		return nil, err
177	}
178	tx.LoadAmount = Float16FromBytes(b[58:60]).BigInt()
179	tx.Amount = Float16FromBytes(b[60:62]).BigInt()
180	tx.TokenID, err = TokenIDFromBytes(b[62:66])
181	if err != nil {
182		return nil, err
183	}
184	tx.ToIdx, err = IdxFromBytes(b[66:72])
185	if err != nil {
186		return nil, err
187	}
188
189	return tx, nil
190}