arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/common/tx.go
common/tx.goRaw
  1package common
  2
  3import (
  4	"bytes"
  5	"database/sql/driver"
  6	"encoding/hex"
  7	"errors"
  8	"fmt"
  9	"math/big"
 10	"strings"
 11
 12	ethCommon "github.com/ethereum/go-ethereum/common"
 13	"github.com/hermeznetwork/tracerr"
 14	"github.com/iden3/go-iden3-crypto/babyjub"
 15)
 16
 17const (
 18	// TXIDPrefixL1UserTx is the prefix that determines that the TxID is
 19	// for a L1UserTx
 20	//nolinter:gomnd
 21	TxIDPrefixL1UserTx = byte(0)
 22
 23	// TXIDPrefixL1CoordTx is the prefix that determines that the TxID is
 24	// for a L1CoordinatorTx
 25	//nolinter:gomnd
 26	TxIDPrefixL1CoordTx = byte(1)
 27
 28	// TxIDPrefixL2Tx is the prefix that determines that the TxID is for a
 29	// L2Tx (or PoolL2Tx)
 30	//nolinter:gomnd
 31	TxIDPrefixL2Tx = byte(2)
 32
 33	// TxIDLen is the length of the TxID byte array
 34	TxIDLen = 33
 35)
 36
 37var (
 38	// SignatureConstantBytes contains the SignatureConstant in byte array
 39	// format, which is equivalent to 3322668559 as uint32 in byte array in
 40	// big endian representation.
 41	SignatureConstantBytes = []byte{198, 11, 230, 15}
 42)
 43
 44// TxID is the identifier of a Hermez network transaction
 45type TxID [TxIDLen]byte
 46
 47// Scan implements Scanner for database/sql.
 48func (txid *TxID) Scan(src interface{}) error {
 49	srcB, ok := src.([]byte)
 50	if !ok {
 51		return tracerr.Wrap(fmt.Errorf("can't scan %T into TxID", src))
 52	}
 53	if len(srcB) != TxIDLen {
 54		return tracerr.Wrap(fmt.Errorf("can't scan []byte of len %d into TxID, need %d", len(srcB), TxIDLen))
 55	}
 56	copy(txid[:], srcB)
 57	return nil
 58}
 59
 60// Value implements valuer for database/sql.
 61func (txid TxID) Value() (driver.Value, error) {
 62	return txid[:], nil
 63}
 64
 65// String returns a string hexadecimal representation of the TxID
 66func (txid TxID) String() string {
 67	return "0x" + hex.EncodeToString(txid[:])
 68}
 69
 70// NewTxIDFromString returns a string hexadecimal representation of the TxID
 71func NewTxIDFromString(idStr string) (TxID, error) {
 72	txid := TxID{}
 73	idStr = strings.TrimPrefix(idStr, "0x")
 74	decoded, err := hex.DecodeString(idStr)
 75	if err != nil {
 76		return TxID{}, tracerr.Wrap(err)
 77	}
 78	if len(decoded) != TxIDLen {
 79		return txid, tracerr.Wrap(errors.New("Invalid idStr"))
 80	}
 81	copy(txid[:], decoded)
 82	return txid, nil
 83}
 84
 85// MarshalText marshals a TxID
 86func (txid TxID) MarshalText() ([]byte, error) {
 87	return []byte(txid.String()), nil
 88}
 89
 90// UnmarshalText unmarshals a TxID
 91func (txid *TxID) UnmarshalText(data []byte) error {
 92	idStr := string(data)
 93	id, err := NewTxIDFromString(idStr)
 94	if err != nil {
 95		return tracerr.Wrap(err)
 96	}
 97	*txid = id
 98	return nil
 99}
100
101// TxType is a string that represents the type of a Hermez network transaction
102type TxType string
103
104const (
105	// TxTypeExit represents L2->L1 token transfer.  A leaf for this account appears in the exit tree of the block
106	TxTypeExit TxType = "Exit"
107	// TxTypeTransfer represents L2->L2 token transfer
108	TxTypeTransfer TxType = "Transfer"
109	// TxTypeDeposit represents L1->L2 transfer
110	TxTypeDeposit TxType = "Deposit"
111	// TxTypeCreateAccountDeposit represents creation of a new leaf in the state tree (newAcconut) + L1->L2 transfer
112	TxTypeCreateAccountDeposit TxType = "CreateAccountDeposit"
113	// TxTypeCreateAccountDepositTransfer represents L1->L2 transfer + L2->L2 transfer
114	TxTypeCreateAccountDepositTransfer TxType = "CreateAccountDepositTransfer"
115	// TxTypeDepositTransfer TBD
116	TxTypeDepositTransfer TxType = "DepositTransfer"
117	// TxTypeForceTransfer TBD
118	TxTypeForceTransfer TxType = "ForceTransfer"
119	// TxTypeForceExit TBD
120	TxTypeForceExit TxType = "ForceExit"
121	// TxTypeTransferToEthAddr TBD
122	TxTypeTransferToEthAddr TxType = "TransferToEthAddr"
123	// TxTypeTransferToBJJ TBD
124	TxTypeTransferToBJJ TxType = "TransferToBJJ"
125)
126
127// Tx is a struct used by the TxSelector & BatchBuilder as a generic type generated from L1Tx & PoolL2Tx
128type Tx struct {
129	// Generic
130	IsL1        bool      `meddler:"is_l1"`
131	TxID        TxID      `meddler:"id"`
132	Type        TxType    `meddler:"type"`
133	Position    int       `meddler:"position"`
134	FromIdx     Idx       `meddler:"from_idx"`
135	ToIdx       Idx       `meddler:"to_idx"`
136	Amount      *big.Int  `meddler:"amount,bigint"`
137	AmountFloat float64   `meddler:"amount_f"`
138	TokenID     TokenID   `meddler:"token_id"`
139	USD         *float64  `meddler:"amount_usd"`
140	BatchNum    *BatchNum `meddler:"batch_num"`     // batchNum in which this tx was forged. If the tx is L2, this must be != 0
141	EthBlockNum int64     `meddler:"eth_block_num"` // Ethereum Block Number in which this L1Tx was added to the queue
142	// L1
143	ToForgeL1TxsNum    *int64                `meddler:"to_forge_l1_txs_num"` // toForgeL1TxsNum in which the tx was forged / will be forged
144	UserOrigin         *bool                 `meddler:"user_origin"`         // 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
145	FromEthAddr        ethCommon.Address     `meddler:"from_eth_addr"`
146	FromBJJ            babyjub.PublicKeyComp `meddler:"from_bjj"`
147	DepositAmount      *big.Int              `meddler:"deposit_amount,bigintnull"`
148	DepositAmountFloat *float64              `meddler:"deposit_amount_f"`
149	DepositAmountUSD   *float64              `meddler:"deposit_amount_usd"`
150	// L2
151	Fee    *FeeSelector `meddler:"fee"`
152	FeeUSD *float64     `meddler:"fee_usd"`
153	Nonce  *Nonce       `meddler:"nonce"`
154}
155
156func (tx *Tx) String() string {
157	buf := bytes.NewBufferString("")
158	fmt.Fprintf(buf, "Type: %s, ", tx.Type)
159	fmt.Fprintf(buf, "FromIdx: %s, ", tx.FromIdx)
160	if tx.Type == TxTypeTransfer ||
161		tx.Type == TxTypeDepositTransfer ||
162		tx.Type == TxTypeCreateAccountDepositTransfer {
163		fmt.Fprintf(buf, "ToIdx: %s, ", tx.ToIdx)
164	}
165	if tx.Type == TxTypeDeposit ||
166		tx.Type == TxTypeDepositTransfer ||
167		tx.Type == TxTypeCreateAccountDepositTransfer {
168		fmt.Fprintf(buf, "DepositAmount: %d, ", tx.DepositAmount)
169	}
170	if tx.Type != TxTypeDeposit {
171		fmt.Fprintf(buf, "Amount: %s, ", tx.Amount)
172	}
173	if tx.Type == TxTypeTransfer ||
174		tx.Type == TxTypeDepositTransfer ||
175		tx.Type == TxTypeCreateAccountDepositTransfer {
176		fmt.Fprintf(buf, "Fee: %d, ", tx.Fee)
177	}
178	fmt.Fprintf(buf, "TokenID: %d", tx.TokenID)
179
180	return buf.String()
181}
182
183// L1Tx returns a *L1Tx from the Tx
184func (tx *Tx) L1Tx() (*L1Tx, error) {
185	return &L1Tx{
186		TxID:            tx.TxID,
187		ToForgeL1TxsNum: tx.ToForgeL1TxsNum,
188		Position:        tx.Position,
189		UserOrigin:      *tx.UserOrigin,
190		FromIdx:         tx.FromIdx,
191		FromEthAddr:     tx.FromEthAddr,
192		FromBJJ:         tx.FromBJJ,
193		ToIdx:           tx.ToIdx,
194		TokenID:         tx.TokenID,
195		Amount:          tx.Amount,
196		DepositAmount:   tx.DepositAmount,
197		EthBlockNum:     tx.EthBlockNum,
198		Type:            tx.Type,
199		BatchNum:        tx.BatchNum,
200	}, nil
201}