github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/state/helper.go (about)

     1  package state
     2  
     3  import (
     4  	"fmt"
     5  	"math/big"
     6  	"strconv"
     7  
     8  	"github.com/0xPolygon/supernets2-node/hex"
     9  	"github.com/0xPolygon/supernets2-node/log"
    10  	"github.com/ethereum/go-ethereum/core/types"
    11  	"github.com/ethereum/go-ethereum/rlp"
    12  )
    13  
    14  const (
    15  	double       = 2
    16  	ether155V    = 27
    17  	etherPre155V = 35
    18  )
    19  
    20  // EncodeTransactions RLP encodes the given transactions
    21  func EncodeTransactions(txs []types.Transaction) ([]byte, error) {
    22  	var batchL2Data []byte
    23  
    24  	for _, tx := range txs {
    25  		v, r, s := tx.RawSignatureValues()
    26  		sign := 1 - (v.Uint64() & 1)
    27  
    28  		nonce, gasPrice, gas, to, value, data, chainID := tx.Nonce(), tx.GasPrice(), tx.Gas(), tx.To(), tx.Value(), tx.Data(), tx.ChainId()
    29  		log.Debug(nonce, " ", gasPrice, " ", gas, " ", to, " ", value, " ", len(data), " ", chainID)
    30  
    31  		rlpFieldsToEncode := []interface{}{
    32  			nonce,
    33  			gasPrice,
    34  			gas,
    35  			to,
    36  			value,
    37  			data,
    38  		}
    39  
    40  		if tx.ChainId().Uint64() > 0 {
    41  			rlpFieldsToEncode = append(rlpFieldsToEncode, chainID)
    42  			rlpFieldsToEncode = append(rlpFieldsToEncode, uint(0))
    43  			rlpFieldsToEncode = append(rlpFieldsToEncode, uint(0))
    44  		}
    45  
    46  		txCodedRlp, err := rlp.EncodeToBytes(rlpFieldsToEncode)
    47  		if err != nil {
    48  			return nil, err
    49  		}
    50  
    51  		newV := new(big.Int).Add(big.NewInt(ether155V), big.NewInt(int64(sign)))
    52  		newRPadded := fmt.Sprintf("%064s", r.Text(hex.Base))
    53  		newSPadded := fmt.Sprintf("%064s", s.Text(hex.Base))
    54  		newVPadded := fmt.Sprintf("%02s", newV.Text(hex.Base))
    55  		txData, err := hex.DecodeString(hex.EncodeToString(txCodedRlp) + newRPadded + newSPadded + newVPadded)
    56  		if err != nil {
    57  			return nil, err
    58  		}
    59  
    60  		batchL2Data = append(batchL2Data, txData...)
    61  	}
    62  
    63  	return batchL2Data, nil
    64  }
    65  
    66  // EncodeTransaction RLP encodes the given transaction
    67  func EncodeTransaction(tx types.Transaction) ([]byte, error) {
    68  	transactions := []types.Transaction{tx}
    69  	return EncodeTransactions(transactions)
    70  }
    71  
    72  // EncodeUnsignedTransaction RLP encodes the given unsigned transaction
    73  func EncodeUnsignedTransaction(tx types.Transaction, chainID uint64, forcedNonce *uint64) ([]byte, error) {
    74  	v, _ := new(big.Int).SetString("0x1c", 0)
    75  	r, _ := new(big.Int).SetString("0xa54492cfacf71aef702421b7fbc70636537a7b2fbe5718c5ed970a001bb7756b", 0)
    76  	s, _ := new(big.Int).SetString("0x2e9fb27acc75955b898f0b12ec52aa34bf08f01db654374484b80bf12f0d841e", 0)
    77  
    78  	sign := 1 - (v.Uint64() & 1)
    79  
    80  	nonce, gasPrice, gas, to, value, data, chainID := tx.Nonce(), tx.GasPrice(), tx.Gas(), tx.To(), tx.Value(), tx.Data(), chainID //nolint:gomnd
    81  	log.Debug(nonce, " ", gasPrice, " ", gas, " ", to, " ", value, " ", len(data), " ", chainID)
    82  
    83  	if forcedNonce != nil {
    84  		nonce = *forcedNonce
    85  		log.Debug("Forced nonce: ", nonce)
    86  	}
    87  
    88  	txCodedRlp, err := rlp.EncodeToBytes([]interface{}{
    89  		nonce,
    90  		gasPrice,
    91  		gas,
    92  		to,
    93  		value,
    94  		data,
    95  		big.NewInt(0).SetUint64(chainID), uint(0), uint(0),
    96  	})
    97  
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  
   102  	newV := new(big.Int).Add(big.NewInt(ether155V), big.NewInt(int64(sign)))
   103  	newRPadded := fmt.Sprintf("%064s", r.Text(hex.Base))
   104  	newSPadded := fmt.Sprintf("%064s", s.Text(hex.Base))
   105  	newVPadded := fmt.Sprintf("%02s", newV.Text(hex.Base))
   106  	txData, err := hex.DecodeString(hex.EncodeToString(txCodedRlp) + newRPadded + newSPadded + newVPadded)
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  
   111  	return txData, nil
   112  }
   113  
   114  // DecodeTxs extracts Transactions for its encoded form
   115  func DecodeTxs(txsData []byte) ([]types.Transaction, []byte, error) {
   116  	// Process coded txs
   117  	var pos uint64
   118  	var txs []types.Transaction
   119  	const (
   120  		headerByteLength uint64 = 1
   121  		sLength          uint64 = 32
   122  		rLength          uint64 = 32
   123  		vLength          uint64 = 1
   124  		c0               uint64 = 192 // 192 is c0. This value is defined by the rlp protocol
   125  		ff               uint64 = 255 // max value of rlp header
   126  		shortRlp         uint64 = 55  // length of the short rlp codification
   127  		f7               uint64 = 247 // 192 + 55 = c0 + shortRlp
   128  	)
   129  	txDataLength := uint64(len(txsData))
   130  	if txDataLength == 0 {
   131  		return txs, txsData, nil
   132  	}
   133  	for pos < txDataLength {
   134  		num, err := strconv.ParseUint(hex.EncodeToString(txsData[pos:pos+1]), hex.Base, hex.BitSize64)
   135  		if err != nil {
   136  			log.Debug("error parsing header length: ", err)
   137  			return []types.Transaction{}, txsData, err
   138  		}
   139  		// First byte is the length and must be ignored
   140  		if num < c0 {
   141  			log.Debugf("error num < c0 : %d, %d", num, c0)
   142  			return []types.Transaction{}, txsData, ErrInvalidData
   143  		}
   144  		length := uint64(num - c0)
   145  		if length > shortRlp { // If rlp is bigger than length 55
   146  			// n is the length of the rlp data without the header (1 byte) for example "0xf7"
   147  			if (pos + 1 + num - f7) > txDataLength {
   148  				log.Debug("error parsing length: ", err)
   149  				return []types.Transaction{}, txsData, err
   150  			}
   151  			n, err := strconv.ParseUint(hex.EncodeToString(txsData[pos+1:pos+1+num-f7]), hex.Base, hex.BitSize64) // +1 is the header. For example 0xf7
   152  			if err != nil {
   153  				log.Debug("error parsing length: ", err)
   154  				return []types.Transaction{}, txsData, err
   155  			}
   156  			if n+num < f7 {
   157  				log.Debug("error n + num < f7: ", err)
   158  				return []types.Transaction{}, txsData, ErrInvalidData
   159  			}
   160  			length = n + num - f7 // num - f7 is the header. For example 0xf7
   161  		}
   162  
   163  		endPos := pos + length + rLength + sLength + vLength + headerByteLength
   164  
   165  		if endPos > txDataLength {
   166  			err := fmt.Errorf("endPos %d is bigger than txDataLength %d", endPos, txDataLength)
   167  			log.Debug("error parsing header: ", err)
   168  			return []types.Transaction{}, txsData, ErrInvalidData
   169  		}
   170  
   171  		fullDataTx := txsData[pos:endPos]
   172  		txInfo := txsData[pos : pos+length+headerByteLength]
   173  		rData := txsData[pos+length+headerByteLength : pos+length+rLength+headerByteLength]
   174  		sData := txsData[pos+length+rLength+headerByteLength : pos+length+rLength+sLength+headerByteLength]
   175  		vData := txsData[pos+length+rLength+sLength+headerByteLength : endPos]
   176  
   177  		pos = endPos
   178  
   179  		// Decode rlpFields
   180  		var rlpFields [][]byte
   181  		err = rlp.DecodeBytes(txInfo, &rlpFields)
   182  		if err != nil {
   183  			log.Error("error decoding tx Bytes: ", err, ". fullDataTx: ", hex.EncodeToString(fullDataTx), "\n tx: ", hex.EncodeToString(txInfo), "\n Txs received: ", hex.EncodeToString(txsData))
   184  			return []types.Transaction{}, txsData, ErrInvalidData
   185  		}
   186  
   187  		legacyTx, err := RlpFieldsToLegacyTx(rlpFields, vData, rData, sData)
   188  		if err != nil {
   189  			log.Debug("error creating tx from rlp fields: ", err, ". fullDataTx: ", hex.EncodeToString(fullDataTx), "\n tx: ", hex.EncodeToString(txInfo), "\n Txs received: ", hex.EncodeToString(txsData))
   190  			return []types.Transaction{}, txsData, err
   191  		}
   192  
   193  		tx := types.NewTx(legacyTx)
   194  		txs = append(txs, *tx)
   195  	}
   196  	return txs, txsData, nil
   197  }
   198  
   199  // DecodeTx decodes a string rlp tx representation into a types.Transaction instance
   200  func DecodeTx(encodedTx string) (*types.Transaction, error) {
   201  	b, err := hex.DecodeHex(encodedTx)
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  
   206  	tx := new(types.Transaction)
   207  	if err := tx.UnmarshalBinary(b); err != nil {
   208  		return nil, err
   209  	}
   210  	return tx, nil
   211  }
   212  
   213  func generateReceipt(blockNumber *big.Int, processedTx *ProcessTransactionResponse) *types.Receipt {
   214  	receipt := &types.Receipt{
   215  		Type:              uint8(processedTx.Type),
   216  		PostState:         processedTx.StateRoot.Bytes(),
   217  		CumulativeGasUsed: processedTx.GasUsed,
   218  		BlockNumber:       blockNumber,
   219  		GasUsed:           processedTx.GasUsed,
   220  		TxHash:            processedTx.Tx.Hash(),
   221  		TransactionIndex:  0,
   222  		ContractAddress:   processedTx.CreateAddress,
   223  		Logs:              processedTx.Logs,
   224  	}
   225  
   226  	// TODO: this fix is temporary while the Executor is returning a
   227  	// different Tx hash for the TxHash, Log.TxHash and Tx.Hash().
   228  	// At the moment, the processedTx.TxHash and Log[n].TxHash are
   229  	// returning a different hash than the Hash of the transaction
   230  	// sent to be processed by the Executor.
   231  	// The processedTx.Tx.Hash() is correct.
   232  	for i := 0; i < len(receipt.Logs); i++ {
   233  		receipt.Logs[i].TxHash = processedTx.Tx.Hash()
   234  	}
   235  	if processedTx.RomError == nil {
   236  		receipt.Status = types.ReceiptStatusSuccessful
   237  	} else {
   238  		receipt.Status = types.ReceiptStatusFailed
   239  	}
   240  
   241  	return receipt
   242  }
   243  
   244  func toPostgresInterval(duration string) (string, error) {
   245  	unit := duration[len(duration)-1]
   246  	var pgUnit string
   247  
   248  	switch unit {
   249  	case 's':
   250  		pgUnit = "second"
   251  	case 'm':
   252  		pgUnit = "minute"
   253  	case 'h':
   254  		pgUnit = "hour"
   255  	default:
   256  		return "", ErrUnsupportedDuration
   257  	}
   258  
   259  	isMoreThanOne := duration[0] != '1' || len(duration) > 2 //nolint:gomnd
   260  	if isMoreThanOne {
   261  		pgUnit = pgUnit + "s"
   262  	}
   263  
   264  	return fmt.Sprintf("%s %s", duration[:len(duration)-1], pgUnit), nil
   265  }