github.com/amazechain/amc@v0.1.3/internal/avm/types/exchange.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "fmt" 6 "github.com/amazechain/amc/common/block" 7 "github.com/amazechain/amc/common/crypto" 8 "github.com/amazechain/amc/common/transaction" 9 "github.com/amazechain/amc/common/types" 10 "github.com/amazechain/amc/internal/avm/common" 11 "github.com/amazechain/amc/internal/avm/rlp" 12 "github.com/amazechain/amc/log" 13 "github.com/amazechain/amc/params" 14 "github.com/holiman/uint256" 15 "golang.org/x/crypto/sha3" 16 "math/big" 17 "sync" 18 "sync/atomic" 19 "time" 20 ) 21 22 // hasherPool holds LegacyKeccak256 hashers for rlpHash. 23 var hasherPool = sync.Pool{ 24 New: func() interface{} { return sha3.NewLegacyKeccak256() }, 25 } 26 27 type writeCounter common.StorageSize 28 29 func (c *writeCounter) Write(b []byte) (int, error) { 30 *c += writeCounter(len(b)) 31 return len(b), nil 32 } 33 34 func ToAmcAddress(addr *common.Address) *types.Address { 35 if addr == nil { 36 return nil 37 } 38 nullAddress := common.Address{} 39 if bytes.Equal(addr[:], nullAddress[:]) { 40 return &types.Address{0} 41 } 42 var a types.Address 43 copy(a[:], addr[:]) 44 return &a 45 } 46 47 func ToAmcAccessList(accessList AccessList) transaction.AccessList { 48 var txAccessList transaction.AccessList 49 for _, accessTuple := range accessList { 50 txAccessTuple := new(transaction.AccessTuple) 51 txAccessTuple.Address = *ToAmcAddress(&accessTuple.Address) 52 for _, hash := range accessTuple.StorageKeys { 53 txAccessTuple.StorageKeys = append(txAccessTuple.StorageKeys, ToAmcHash(hash)) 54 } 55 txAccessList = append(txAccessList, *txAccessTuple) 56 } 57 return txAccessList 58 } 59 60 func FromAmcAccessList(accessList transaction.AccessList) AccessList { 61 var txAccessList AccessList 62 for _, accessTuple := range accessList { 63 txAccessTuple := new(AccessTuple) 64 txAccessTuple.Address = *FromAmcAddress(&accessTuple.Address) 65 for _, hash := range accessTuple.StorageKeys { 66 txAccessTuple.StorageKeys = append(txAccessTuple.StorageKeys, FromAmcHash(hash)) 67 } 68 txAccessList = append(txAccessList, *txAccessTuple) 69 } 70 return txAccessList 71 } 72 73 func FromAmcAddress(address *types.Address) *common.Address { 74 if address == nil { 75 return nil 76 } 77 var a common.Address 78 copy(a[:], address[:]) 79 return &a 80 } 81 82 func ToAmcHash(hash common.Hash) types.Hash { 83 var h types.Hash 84 copy(h[:], hash[:]) 85 return h 86 } 87 88 func FromAmcHash(hash types.Hash) common.Hash { 89 var h common.Hash 90 copy(h[:], hash[:]) 91 return h 92 } 93 94 func ToAmcLog(log *Log) *block.Log { 95 if log == nil { 96 return nil 97 } 98 99 var topics []types.Hash 100 for _, topic := range log.Topics { 101 topics = append(topics, ToAmcHash(topic)) 102 } 103 104 return &block.Log{ 105 Address: *ToAmcAddress(&log.Address), 106 Topics: topics, 107 Data: log.Data, 108 BlockNumber: uint256.NewInt(log.BlockNumber), 109 TxHash: ToAmcHash(log.TxHash), 110 TxIndex: log.TxIndex, 111 BlockHash: ToAmcHash(log.BlockHash), 112 Index: log.Index, 113 Removed: log.Removed, 114 } 115 } 116 117 func FromAmcLog(log *block.Log) *Log { 118 if log == nil { 119 return nil 120 } 121 122 var topics []common.Hash 123 for _, topic := range log.Topics { 124 topics = append(topics, FromAmcHash(topic)) 125 } 126 127 return &Log{ 128 Address: *FromAmcAddress(&log.Address), 129 Topics: topics, 130 Data: log.Data, 131 BlockNumber: log.BlockNumber.Uint64(), 132 TxHash: FromAmcHash(log.TxHash), 133 TxIndex: log.TxIndex, 134 BlockHash: FromAmcHash(log.BlockHash), 135 Index: log.Index, 136 Removed: log.Removed, 137 } 138 } 139 140 func ToAmcLogs(logs []*Log) []*block.Log { 141 var amcLogs []*block.Log 142 for _, log := range logs { 143 amcLogs = append(amcLogs, ToAmcLog(log)) 144 } 145 return amcLogs 146 } 147 148 func FromAmcLogs(amcLogs []*block.Log) []*Log { 149 var logs []*Log 150 for _, log := range amcLogs { 151 logs = append(logs, FromAmcLog(log)) 152 } 153 return logs 154 } 155 156 type Transaction struct { 157 inner TxData // Consensus contents of a transaction 158 time time.Time // Time first seen locally (spam avoidance) 159 160 // caches 161 hash atomic.Value 162 size atomic.Value 163 from atomic.Value 164 } 165 166 // NewTx creates a new transaction. 167 func NewTx(inner TxData) *Transaction { 168 tx := new(Transaction) 169 tx.setDecoded(inner.copy(), 0) 170 return tx 171 } 172 173 // Hash returns the transaction hash. 174 func (tx *Transaction) Hash() common.Hash { 175 if hash := tx.hash.Load(); hash != nil { 176 return hash.(common.Hash) 177 } 178 179 var h common.Hash 180 if tx.Type() == LegacyTxType { 181 h = rlpHash(tx.inner) 182 } else { 183 h = prefixedRlpHash(tx.Type(), tx.inner) 184 } 185 tx.hash.Store(h) 186 return h 187 } 188 189 func isProtectedV(V *big.Int) bool { 190 if V.BitLen() <= 8 { 191 v := V.Uint64() 192 return v != 27 && v != 28 && v != 1 && v != 0 193 } 194 // anything not 27 or 28 is considered protected 195 return true 196 } 197 198 // Protected says whether the transaction is replay-protected. 199 func (tx *Transaction) Protected() bool { 200 switch tx := tx.inner.(type) { 201 case *LegacyTx: 202 return tx.V != nil && isProtectedV(tx.V) 203 default: 204 return true 205 } 206 } 207 208 // Type returns the transaction type. 209 func (tx *Transaction) Type() uint8 { 210 return tx.inner.txType() 211 } 212 213 // ChainId returns the EIP155 chain ID of the transaction. The return value will always be 214 // non-nil. For legacy transactions which are not replay-protected, the return value is 215 // zero. 216 func (tx *Transaction) ChainId() *big.Int { 217 return tx.inner.chainID() 218 } 219 220 // Data returns the input data of the transaction. 221 func (tx *Transaction) Data() []byte { return tx.inner.data() } 222 223 // AccessList returns the access list of the transaction. 224 func (tx *Transaction) AccessList() AccessList { return tx.inner.accessList() } 225 226 // Gas returns the gas limit of the transaction. 227 func (tx *Transaction) Gas() uint64 { return tx.inner.gas() } 228 229 // GasPrice returns the gas price of the transaction. 230 func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.inner.gasPrice()) } 231 232 // GasTipCap returns the gasTipCap per gas of the transaction. 233 func (tx *Transaction) GasTipCap() *big.Int { return new(big.Int).Set(tx.inner.gasTipCap()) } 234 235 // GasFeeCap returns the fee cap per gas of the transaction. 236 func (tx *Transaction) GasFeeCap() *big.Int { return new(big.Int).Set(tx.inner.gasFeeCap()) } 237 238 // Value returns the ether amount of the transaction. 239 func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.inner.value()) } 240 241 // Nonce returns the sender account nonce of the transaction. 242 func (tx *Transaction) Nonce() uint64 { return tx.inner.nonce() } 243 244 // To returns the recipient address of the transaction. 245 // For contract-creation transactions, To returns nil. 246 func (tx *Transaction) To() *common.Address { 247 return copyAddressPtr(tx.inner.to()) 248 } 249 250 func (tx *Transaction) RawSignatureValues() (v, r, s *big.Int) { 251 return tx.inner.rawSignatureValues() 252 } 253 254 // Size returns the true RLP encoded storage size of the transaction, either by 255 // encoding and returning it, or returning a previously cached value. 256 func (tx *Transaction) Size() common.StorageSize { 257 if size := tx.size.Load(); size != nil { 258 return size.(common.StorageSize) 259 } 260 c := writeCounter(0) 261 rlp.Encode(&c, &tx.inner) 262 tx.size.Store(common.StorageSize(c)) 263 return common.StorageSize(c) 264 } 265 266 // WithSignature returns a new transaction with the given signature. 267 // This signature needs to be in the [R || S || V] format where V is 0 or 1. 268 func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, error) { 269 r, s, v, err := signer.SignatureValues(tx, sig) 270 if err != nil { 271 return nil, err 272 } 273 cpy := tx.inner.copy() 274 cpy.setSignatureValues(signer.ChainID(), v, r, s) 275 return &Transaction{inner: cpy, time: tx.time}, nil 276 } 277 278 // UnmarshalBinary 279 func (tx *Transaction) UnmarshalBinary(b []byte) error { 280 if len(b) > 0 && b[0] > 0x7f { 281 // It's a legacy transaction. 282 var data LegacyTx 283 err := rlp.DecodeBytes(b, &data) 284 if err != nil { 285 return err 286 } 287 tx.setDecoded(&data, len(b)) 288 return nil 289 } 290 // It's an EIP2718 typed transaction envelope. 291 inner, err := tx.decodeTyped(b) 292 if err != nil { 293 return err 294 } 295 tx.setDecoded(inner, len(b)) 296 return nil 297 } 298 299 // decodeTyped decodes a typed transaction from the canonical format. 300 func (tx *Transaction) decodeTyped(b []byte) (TxData, error) { 301 if len(b) <= 1 { 302 return nil, fmt.Errorf("typed transaction too short") 303 } 304 switch b[0] { 305 case AccessListTxType: 306 var inner AccessListTx 307 err := rlp.DecodeBytes(b[1:], &inner) 308 return &inner, err 309 case DynamicFeeTxType: 310 var inner DynamicFeeTx 311 err := rlp.DecodeBytes(b[1:], &inner) 312 return &inner, err 313 default: 314 return nil, fmt.Errorf("transaction type not valid in this context") 315 } 316 } 317 318 // setDecoded sets the inner transaction and size after decoding. 319 func (tx *Transaction) setDecoded(inner TxData, size int) { 320 tx.inner = inner 321 tx.time = time.Now() 322 if size > 0 { 323 tx.size.Store(common.StorageSize(size)) 324 } 325 } 326 327 func (tx *Transaction) ToAmcTransaction(chainConfig *params.ChainConfig, blockNumber *big.Int) (*transaction.Transaction, error) { 328 329 var inner transaction.TxData 330 gasPrice, overflow := uint256.FromBig(tx.GasPrice()) 331 if overflow { 332 return nil, fmt.Errorf("cannot convert big int to int256") 333 } 334 335 vl, overflow := uint256.FromBig(tx.Value()) 336 if overflow { 337 return nil, fmt.Errorf("cannot convert big int to int256") 338 } 339 340 signer := MakeSigner(chainConfig, blockNumber) 341 from, err := Sender(signer, tx) 342 if err != nil { 343 return nil, err 344 } 345 346 v, r, s := tx.RawSignatureValues() 347 V, is1 := uint256.FromBig(v) 348 R, is2 := uint256.FromBig(r) 349 S, is3 := uint256.FromBig(s) 350 if is1 || is2 || is3 { 351 return nil, fmt.Errorf("r,s,v overflow") 352 } 353 switch tx.Type() { 354 case LegacyTxType: 355 inner = &transaction.LegacyTx{ 356 Nonce: tx.Nonce(), 357 Gas: tx.Gas(), 358 Data: common.CopyBytes(tx.Data()), 359 GasPrice: gasPrice, 360 Value: vl, 361 To: ToAmcAddress(tx.To()), 362 From: ToAmcAddress(&from), 363 V: V, 364 R: R, 365 S: S, 366 } 367 368 log.Debug("tx type is LegacyTxType") 369 case AccessListTxType: 370 at := &transaction.AccessListTx{ 371 Nonce: tx.Nonce(), 372 Gas: tx.Gas(), 373 Data: common.CopyBytes(tx.Data()), 374 To: ToAmcAddress(tx.To()), 375 GasPrice: gasPrice, 376 Value: vl, 377 From: ToAmcAddress(&from), 378 AccessList: ToAmcAccessList(tx.AccessList()), 379 V: V, 380 R: R, 381 S: S, 382 } 383 at.ChainID, _ = uint256.FromBig(tx.ChainId()) 384 inner = at 385 log.Debug("tx type is AccessListTxType") 386 case DynamicFeeTxType: 387 dft := &transaction.DynamicFeeTx{ 388 Nonce: tx.Nonce(), 389 Gas: tx.Gas(), 390 To: ToAmcAddress(tx.To()), 391 Data: common.CopyBytes(tx.Data()), 392 AccessList: ToAmcAccessList(tx.AccessList()), 393 Value: vl, 394 From: ToAmcAddress(&from), 395 V: V, 396 R: R, 397 S: S, 398 } 399 dft.ChainID, _ = uint256.FromBig(tx.ChainId()) 400 dft.GasTipCap, _ = uint256.FromBig(tx.GasTipCap()) 401 dft.GasFeeCap, _ = uint256.FromBig(tx.GasFeeCap()) 402 inner = dft 403 log.Debug("tx type is DynamicFeeTxType") 404 } 405 406 amcTx := transaction.NewTx(inner) 407 return amcTx, nil 408 } 409 410 func (tx *Transaction) FromAmcTransaction(amcTx *transaction.Transaction) { 411 412 var inner TxData 413 414 gasPrice := amcTx.GasPrice().ToBig() 415 vl := amcTx.Value().ToBig() 416 417 switch amcTx.Type() { 418 case transaction.LegacyTxType: 419 inner = &LegacyTx{ 420 Nonce: amcTx.Nonce(), 421 Gas: amcTx.Gas(), 422 Data: common.CopyBytes(amcTx.Data()), 423 GasPrice: gasPrice, 424 Value: vl, 425 To: FromAmcAddress(amcTx.To()), 426 } 427 428 case transaction.AccessListTxType: 429 at := &AccessListTx{ 430 Nonce: amcTx.Nonce(), 431 Gas: amcTx.Gas(), 432 Data: common.CopyBytes(amcTx.Data()), 433 To: FromAmcAddress(amcTx.To()), 434 GasPrice: gasPrice, 435 Value: vl, 436 AccessList: FromAmcAccessList(amcTx.AccessList()), 437 } 438 at.ChainID = amcTx.ChainId().ToBig() 439 inner = at 440 441 case transaction.DynamicFeeTxType: 442 dft := &DynamicFeeTx{ 443 Nonce: amcTx.Nonce(), 444 Gas: amcTx.Gas(), 445 To: FromAmcAddress(amcTx.To()), 446 Data: common.CopyBytes(amcTx.Data()), 447 AccessList: FromAmcAccessList(amcTx.AccessList()), 448 Value: vl, 449 } 450 dft.ChainID = amcTx.ChainId().ToBig() 451 dft.GasTipCap = amcTx.GasTipCap().ToBig() 452 dft.GasFeeCap = amcTx.GasFeeCap().ToBig() 453 inner = dft 454 } 455 456 v, r, s := amcTx.RawSignatureValues() 457 inner.setSignatureValues(amcTx.ChainId().ToBig(), v.ToBig(), r.ToBig(), s.ToBig()) 458 459 tx.setDecoded(inner.copy(), 0) 460 } 461 462 func FromAmcHeader(iHeader block.IHeader) *Header { 463 header := iHeader.(*block.Header) 464 //author, _ := engine.Author(iHeader) 465 466 var baseFee *big.Int 467 if header.BaseFee != nil { 468 baseFee = header.BaseFee.ToBig() 469 } 470 471 bloom := new(Bloom) 472 bloom.SetBytes(header.Bloom.Bytes()) 473 474 return &Header{ 475 ParentHash: FromAmcHash(header.ParentHash), 476 UncleHash: FromAmcHash(EmptyUncleHash), 477 Coinbase: *FromAmcAddress(&header.Coinbase), 478 Root: FromAmcHash(header.Root), 479 TxHash: FromAmcHash(header.TxHash), 480 ReceiptHash: FromAmcHash(header.ReceiptHash), 481 Difficulty: header.Difficulty.ToBig(), 482 Number: header.Number.ToBig(), 483 GasLimit: header.GasLimit, 484 GasUsed: header.GasUsed, 485 Time: header.Time, 486 Extra: header.Extra, 487 MixDigest: FromAmcHash(header.MixDigest), 488 Nonce: EncodeNonce(header.Nonce.Uint64()), 489 BaseFee: baseFee, 490 Bloom: *bloom, 491 } 492 } 493 494 func rlpHash(x interface{}) (h common.Hash) { 495 sha := hasherPool.Get().(crypto.KeccakState) 496 defer hasherPool.Put(sha) 497 sha.Reset() 498 rlp.Encode(sha, x) 499 sha.Read(h[:]) 500 return h 501 } 502 503 // prefixedRlpHash writes the prefix into the hasher before rlp-encoding x. 504 // It's used for typed transactions. 505 func prefixedRlpHash(prefix byte, x interface{}) (h common.Hash) { 506 sha := hasherPool.Get().(crypto.KeccakState) 507 defer hasherPool.Put(sha) 508 sha.Reset() 509 sha.Write([]byte{prefix}) 510 rlp.Encode(sha, x) 511 sha.Read(h[:]) 512 return h 513 }