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 == nil {
 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	var toForge uint64 = 0
 87	if l1Tx.ToForgeL1TxsNum != nil {
 88		toForge = uint64(*l1Tx.ToForgeL1TxsNum)
 89	}
 90	binary.BigEndian.PutUint64(toForgeL1TxsNumBytes[:], toForge)
 91	copy(txid[1:9], toForgeL1TxsNumBytes[:])
 92
 93	var positionBytes [2]byte
 94	binary.BigEndian.PutUint16(positionBytes[:], uint16(l1Tx.Position))
 95	copy(txid[9:11], positionBytes[:])
 96	l1Tx.TxID = TxID(txid)
 97
 98	return l1Tx, nil
 99}
100
101// Tx returns a *Tx from the L1Tx
102func (tx *L1Tx) Tx() *Tx {
103	f := new(big.Float).SetInt(tx.Amount)
104	amountFloat, _ := f.Float64()
105	userOrigin := new(bool)
106	*userOrigin = tx.UserOrigin
107	fromEthAddr := new(ethCommon.Address)
108	*fromEthAddr = tx.FromEthAddr
109	toIdx := new(Idx)
110	*toIdx = tx.ToIdx
111	genericTx := &Tx{
112		IsL1:            true,
113		TxID:            tx.TxID,
114		Type:            tx.Type,
115		Position:        tx.Position,
116		FromIdx:         tx.FromIdx,
117		ToIdx:           toIdx,
118		Amount:          tx.Amount,
119		AmountFloat:     amountFloat,
120		TokenID:         tx.TokenID,
121		ToForgeL1TxsNum: tx.ToForgeL1TxsNum,
122		UserOrigin:      userOrigin,
123		FromEthAddr:     fromEthAddr,
124		FromBJJ:         tx.FromBJJ,
125		LoadAmount:      tx.LoadAmount,
126		EthBlockNum:     tx.EthBlockNum,
127		USD:             tx.USD,
128		LoadAmountUSD:   tx.LoadAmountUSD,
129	}
130	if tx.LoadAmount != nil {
131		lf := new(big.Float).SetInt(tx.LoadAmount)
132		loadAmountFloat, _ := lf.Float64()
133		genericTx.LoadAmountFloat = &loadAmountFloat
134	}
135	return genericTx
136}
137
138// Bytes encodes a L1Tx into []byte
139func (tx *L1Tx) Bytes(nLevels int) ([]byte, error) {
140	var b [L1TxBytesLen]byte
141	copy(b[0:20], tx.FromEthAddr.Bytes())
142	pkComp := tx.FromBJJ.Compress()
143	copy(b[20:52], pkComp[:])
144	fromIdxBytes, err := tx.FromIdx.Bytes()
145	if err != nil {
146		return nil, err
147	}
148	copy(b[52:58], fromIdxBytes[:])
149	loadAmountFloat16, err := NewFloat16(tx.LoadAmount)
150	if err != nil {
151		return nil, err
152	}
153	copy(b[58:60], loadAmountFloat16.Bytes())
154	amountFloat16, err := NewFloat16(tx.Amount)
155	if err != nil {
156		return nil, err
157	}
158	copy(b[60:62], amountFloat16.Bytes())
159	copy(b[62:66], tx.TokenID.Bytes())
160	toIdxBytes, err := tx.ToIdx.Bytes()
161	if err != nil {
162		return nil, err
163	}
164	copy(b[66:72], toIdxBytes[:])
165	return b[:], nil
166}
167
168// L1TxFromBytes decodes a L1Tx from []byte
169func L1TxFromBytes(b []byte) (*L1Tx, error) {
170	if len(b) != L1TxBytesLen {
171		return nil, fmt.Errorf("Can not parse L1Tx bytes, expected length %d, current: %d", 68, len(b))
172	}
173
174	tx := &L1Tx{}
175	var err error
176	tx.FromEthAddr = ethCommon.BytesToAddress(b[0:20])
177	pkCompB := b[20:52]
178	var pkComp babyjub.PublicKeyComp
179	copy(pkComp[:], pkCompB)
180	tx.FromBJJ, err = pkComp.Decompress()
181	if err != nil {
182		return nil, err
183	}
184	fromIdx, err := IdxFromBytes(b[52:58])
185	if err != nil {
186		return nil, err
187	}
188	if fromIdx != 0 {
189		tx.FromIdx = new(Idx)
190		*tx.FromIdx = fromIdx
191	}
192	tx.LoadAmount = Float16FromBytes(b[58:60]).BigInt()
193	tx.Amount = Float16FromBytes(b[60:62]).BigInt()
194	tx.TokenID, err = TokenIDFromBytes(b[62:66])
195	if err != nil {
196		return nil, err
197	}
198	tx.ToIdx, err = IdxFromBytes(b[66:72])
199	if err != nil {
200		return nil, err
201	}
202
203	return tx, nil
204}