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