github.com/baptiste-b-pegasys/quorum/v22@v22.4.2/core/types/transaction_marshalling.go (about) 1 package types 2 3 import ( 4 "encoding/json" 5 "errors" 6 "math/big" 7 8 "github.com/ethereum/go-ethereum/common" 9 "github.com/ethereum/go-ethereum/common/hexutil" 10 ) 11 12 // txJSON is the JSON representation of transactions. 13 type txJSON struct { 14 Type hexutil.Uint64 `json:"type"` 15 16 // Common transaction fields: 17 Nonce *hexutil.Uint64 `json:"nonce"` 18 GasPrice *hexutil.Big `json:"gasPrice"` 19 Gas *hexutil.Uint64 `json:"gas"` 20 Value *hexutil.Big `json:"value"` 21 Data *hexutil.Bytes `json:"input"` 22 V *hexutil.Big `json:"v"` 23 R *hexutil.Big `json:"r"` 24 S *hexutil.Big `json:"s"` 25 To *common.Address `json:"to"` 26 27 // Access list transaction fields: 28 ChainID *hexutil.Big `json:"chainId,omitempty"` 29 AccessList *AccessList `json:"accessList,omitempty"` 30 31 // Only used for encoding: 32 Hash common.Hash `json:"hash"` 33 } 34 35 // MarshalJSON marshals as JSON with a hash. 36 func (t *Transaction) MarshalJSON() ([]byte, error) { 37 var enc txJSON 38 // These are set for all tx types. 39 enc.Hash = t.Hash() 40 enc.Type = hexutil.Uint64(t.Type()) 41 42 // Other fields are set conditionally depending on tx type. 43 switch tx := t.inner.(type) { 44 case *LegacyTx: 45 enc.Nonce = (*hexutil.Uint64)(&tx.Nonce) 46 enc.Gas = (*hexutil.Uint64)(&tx.Gas) 47 enc.GasPrice = (*hexutil.Big)(tx.GasPrice) 48 enc.Value = (*hexutil.Big)(tx.Value) 49 enc.Data = (*hexutil.Bytes)(&tx.Data) 50 enc.To = t.To() 51 enc.V = (*hexutil.Big)(tx.V) 52 enc.R = (*hexutil.Big)(tx.R) 53 enc.S = (*hexutil.Big)(tx.S) 54 case *AccessListTx: 55 enc.ChainID = (*hexutil.Big)(tx.ChainID) 56 enc.AccessList = &tx.AccessList 57 enc.Nonce = (*hexutil.Uint64)(&tx.Nonce) 58 enc.Gas = (*hexutil.Uint64)(&tx.Gas) 59 enc.GasPrice = (*hexutil.Big)(tx.GasPrice) 60 enc.Value = (*hexutil.Big)(tx.Value) 61 enc.Data = (*hexutil.Bytes)(&tx.Data) 62 enc.To = t.To() 63 enc.V = (*hexutil.Big)(tx.V) 64 enc.R = (*hexutil.Big)(tx.R) 65 enc.S = (*hexutil.Big)(tx.S) 66 } 67 return json.Marshal(&enc) 68 } 69 70 // UnmarshalJSON unmarshals from JSON. 71 func (t *Transaction) UnmarshalJSON(input []byte) error { 72 var dec txJSON 73 if err := json.Unmarshal(input, &dec); err != nil { 74 return err 75 } 76 77 // Decode / verify fields according to transaction type. 78 var inner TxData 79 switch dec.Type { 80 case LegacyTxType: 81 var itx LegacyTx 82 inner = &itx 83 if dec.To != nil { 84 itx.To = dec.To 85 } 86 if dec.Nonce == nil { 87 return errors.New("missing required field 'nonce' in transaction") 88 } 89 itx.Nonce = uint64(*dec.Nonce) 90 if dec.GasPrice == nil { 91 return errors.New("missing required field 'gasPrice' in transaction") 92 } 93 itx.GasPrice = (*big.Int)(dec.GasPrice) 94 if dec.Gas == nil { 95 return errors.New("missing required field 'gas' in transaction") 96 } 97 itx.Gas = uint64(*dec.Gas) 98 if dec.Value == nil { 99 return errors.New("missing required field 'value' in transaction") 100 } 101 itx.Value = (*big.Int)(dec.Value) 102 if dec.Data == nil { 103 return errors.New("missing required field 'input' in transaction") 104 } 105 itx.Data = *dec.Data 106 if dec.V == nil { 107 return errors.New("missing required field 'v' in transaction") 108 } 109 itx.V = (*big.Int)(dec.V) 110 if dec.R == nil { 111 return errors.New("missing required field 'r' in transaction") 112 } 113 itx.R = (*big.Int)(dec.R) 114 if dec.S == nil { 115 return errors.New("missing required field 's' in transaction") 116 } 117 itx.S = (*big.Int)(dec.S) 118 withSignature := itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 119 if withSignature { 120 if err := sanityCheckSignature(itx.V, itx.R, itx.S, true); err != nil { 121 return err 122 } 123 } 124 125 case AccessListTxType: 126 var itx AccessListTx 127 inner = &itx 128 // Access list is optional for now. 129 if dec.AccessList != nil { 130 itx.AccessList = *dec.AccessList 131 } 132 if dec.ChainID == nil { 133 return errors.New("missing required field 'chainId' in transaction") 134 } 135 itx.ChainID = (*big.Int)(dec.ChainID) 136 if dec.To != nil { 137 itx.To = dec.To 138 } 139 if dec.Nonce == nil { 140 return errors.New("missing required field 'nonce' in transaction") 141 } 142 itx.Nonce = uint64(*dec.Nonce) 143 if dec.GasPrice == nil { 144 return errors.New("missing required field 'gasPrice' in transaction") 145 } 146 itx.GasPrice = (*big.Int)(dec.GasPrice) 147 if dec.Gas == nil { 148 return errors.New("missing required field 'gas' in transaction") 149 } 150 itx.Gas = uint64(*dec.Gas) 151 if dec.Value == nil { 152 return errors.New("missing required field 'value' in transaction") 153 } 154 itx.Value = (*big.Int)(dec.Value) 155 if dec.Data == nil { 156 return errors.New("missing required field 'input' in transaction") 157 } 158 itx.Data = *dec.Data 159 if dec.V == nil { 160 return errors.New("missing required field 'v' in transaction") 161 } 162 itx.V = (*big.Int)(dec.V) 163 if dec.R == nil { 164 return errors.New("missing required field 'r' in transaction") 165 } 166 itx.R = (*big.Int)(dec.R) 167 if dec.S == nil { 168 return errors.New("missing required field 's' in transaction") 169 } 170 itx.S = (*big.Int)(dec.S) 171 withSignature := itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 172 if withSignature { 173 if err := sanityCheckSignature(itx.V, itx.R, itx.S, false); err != nil { 174 return err 175 } 176 } 177 178 default: 179 return ErrTxTypeNotSupported 180 } 181 182 // Now set the inner transaction. 183 t.setDecoded(inner, 0) 184 185 // TODO: check hash here? 186 return nil 187 }