github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/eth/bind.go (about) 1 // Copyright 2015 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The Spectrum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the Spectrum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package eth 18 19 import ( 20 "context" 21 "math/big" 22 23 "github.com/SmartMeshFoundation/Spectrum" 24 "github.com/SmartMeshFoundation/Spectrum/common" 25 "github.com/SmartMeshFoundation/Spectrum/common/hexutil" 26 "github.com/SmartMeshFoundation/Spectrum/core/types" 27 "github.com/SmartMeshFoundation/Spectrum/internal/ethapi" 28 "github.com/SmartMeshFoundation/Spectrum/log" 29 "github.com/SmartMeshFoundation/Spectrum/rlp" 30 "github.com/SmartMeshFoundation/Spectrum/rpc" 31 ) 32 33 // ContractBackend implements bind.ContractBackend with direct calls to Ethereum 34 // internals to support operating on contracts within subprotocols like eth and 35 // swarm. 36 // 37 // Internally this backend uses the already exposed API endpoints of the Ethereum 38 // object. These should be rewritten to internal Go method calls when the Go API 39 // is refactored to support a clean library use. 40 type ContractBackend struct { 41 eapi *ethapi.PublicEthereumAPI // Wrapper around the Ethereum object to access metadata 42 bcapi *ethapi.PublicBlockChainAPI // Wrapper around the blockchain to access chain data 43 txapi *ethapi.PublicTransactionPoolAPI // Wrapper around the transaction pool to access transaction data 44 } 45 46 // NewContractBackend creates a new native contract backend using an existing 47 // Ethereum object. 48 func NewContractBackend(apiBackend ethapi.Backend) *ContractBackend { 49 return &ContractBackend{ 50 eapi: ethapi.NewPublicEthereumAPI(apiBackend), 51 bcapi: ethapi.NewPublicBlockChainAPI(apiBackend), 52 txapi: ethapi.NewPublicTransactionPoolAPI(apiBackend, new(ethapi.AddrLocker)), 53 } 54 } 55 56 // CodeAt retrieves any code associated with the contract from the local API. 57 func (b *ContractBackend) CodeAt(ctx context.Context, contract common.Address, blockNum *big.Int) ([]byte, error) { 58 return b.bcapi.GetCode(ctx, contract, toBlockNumber(blockNum)) 59 } 60 61 // CodeAt retrieves any code associated with the contract from the local API. 62 func (b *ContractBackend) PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) { 63 return b.bcapi.GetCode(ctx, contract, rpc.PendingBlockNumber) 64 } 65 66 // ContractCall implements bind.ContractCaller executing an Ethereum contract 67 // call with the specified data as the input. The pending flag requests execution 68 // against the pending block, not the stable head of the chain. 69 func (b *ContractBackend) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNum *big.Int) ([]byte, error) { 70 out, err := b.bcapi.Call(ctx, toCallArgs(msg), toBlockNumber(blockNum), nil) 71 return out, err 72 } 73 74 func (b *ContractBackend) CallContractWithHash(ctx context.Context, msg ethereum.CallMsg, blockHash common.Hash) ([]byte, error) { 75 out, err := b.bcapi.Call(ctx, toCallArgs(msg), toBlockNumber(nil), &blockHash) 76 return out, err 77 } 78 79 // ContractCall implements bind.ContractCaller executing an Ethereum contract 80 // call with the specified data as the input. The pending flag requests execution 81 // against the pending block, not the stable head of the chain. 82 func (b *ContractBackend) PendingCallContract(ctx context.Context, msg ethereum.CallMsg) ([]byte, error) { 83 out, err := b.bcapi.Call(ctx, toCallArgs(msg), rpc.PendingBlockNumber, nil) 84 return out, err 85 } 86 87 func toCallArgs(msg ethereum.CallMsg) ethapi.CallArgs { 88 args := ethapi.CallArgs{ 89 To: msg.To, 90 From: msg.From, 91 Data: msg.Data, 92 } 93 if msg.Gas != nil { 94 args.Gas = hexutil.Big(*msg.Gas) 95 } 96 if msg.GasPrice != nil { 97 args.GasPrice = hexutil.Big(*msg.GasPrice) 98 } 99 if msg.Value != nil { 100 args.Value = hexutil.Big(*msg.Value) 101 } 102 return args 103 } 104 105 func toBlockNumber(num *big.Int) rpc.BlockNumber { 106 if num == nil { 107 return rpc.LatestBlockNumber 108 } 109 return rpc.BlockNumber(num.Int64()) 110 } 111 112 // PendingAccountNonce implements bind.ContractTransactor retrieving the current 113 // pending nonce associated with an account. 114 func (b *ContractBackend) PendingNonceAt(ctx context.Context, account common.Address) (nonce uint64, err error) { 115 out, err := b.txapi.GetTransactionCount(ctx, account, rpc.PendingBlockNumber) 116 if out != nil { 117 nonce = uint64(*out) 118 } 119 return nonce, err 120 } 121 122 // SuggestGasPrice implements bind.ContractTransactor retrieving the currently 123 // suggested gas price to allow a timely execution of a transaction. 124 func (b *ContractBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) { 125 return b.eapi.GasPrice(ctx) 126 } 127 128 // EstimateGasLimit implements bind.ContractTransactor triing to estimate the gas 129 // needed to execute a specific transaction based on the current pending state of 130 // the backend blockchain. There is no guarantee that this is the true gas limit 131 // requirement as other transactions may be added or removed by miners, but it 132 // should provide a basis for setting a reasonable default. 133 func (b *ContractBackend) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (*big.Int, error) { 134 out, err := b.bcapi.EstimateGas(ctx, toCallArgs(msg)) 135 return out.ToInt(), err 136 } 137 138 // SendTransaction implements bind.ContractTransactor injects the transaction 139 // into the pending pool for execution. 140 func (b *ContractBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error { 141 log.Debug("ContractBackend.SendTransaction", "tx", tx.Hash().Hex()) 142 raw, _ := rlp.EncodeToBytes(tx) 143 _, err := b.txapi.SendRawTransaction(ctx, raw) 144 return err 145 }