github.com/codingfuture/orig-energi3@v0.8.4/eth/contract_api.go (about) 1 // Copyright 2019 The Energi Core Authors 2 // This file is part of the Energi Core library. 3 // 4 // The Energi Core 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 Energi Core 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 Energi Core library. If not, see <http://www.gnu.org/licenses/>. 16 17 package eth 18 19 import ( 20 "context" 21 "errors" 22 "math/big" 23 24 "github.com/ethereum/go-ethereum" 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/core" 27 "github.com/ethereum/go-ethereum/core/types" 28 "github.com/ethereum/go-ethereum/core/vm" 29 "github.com/ethereum/go-ethereum/event" 30 "github.com/ethereum/go-ethereum/rpc" 31 32 energi_common "energi.world/core/gen3/energi/common" 33 energi_params "energi.world/core/gen3/energi/params" 34 ) 35 36 func (b *EthAPIBackend) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) { 37 rpcBlockNumber := rpc.LatestBlockNumber 38 39 if blockNumber != nil { 40 rpcBlockNumber = rpc.BlockNumber(blockNumber.Int64()) 41 } 42 43 state, _, err := b.StateAndHeaderByNumber(ctx, rpcBlockNumber) 44 if err != nil { 45 return nil, err 46 } 47 48 return state.GetCode(contract), nil 49 } 50 51 func (b *EthAPIBackend) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { 52 rpcBlockNumber := rpc.LatestBlockNumber 53 54 if blockNumber != nil { 55 rpcBlockNumber = rpc.BlockNumber(blockNumber.Int64()) 56 } 57 58 state, header, err := b.StateAndHeaderByNumber(ctx, rpcBlockNumber) 59 if err != nil { 60 return nil, err 61 } 62 63 if call.Gas == 0 { 64 call.Gas = 100000 65 } 66 67 msg := types.NewMessage( 68 energi_params.Energi_SystemFaucet, 69 call.To, 70 0, 71 common.Big0, 72 call.Gas, 73 common.Big0, 74 call.Data, 75 false, 76 ) 77 78 evmctx := core.NewEVMContext(msg, header, b.eth.blockchain, &header.Coinbase) 79 vmenv := vm.NewEVM(evmctx, state, b.eth.chainConfig, *b.eth.blockchain.GetVMConfig()) 80 gaspool := new(core.GasPool).AddGas(call.Gas) 81 82 ret, _, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb() 83 return ret, err 84 } 85 86 func (b *EthAPIBackend) PendingCodeAt( 87 ctx context.Context, 88 account common.Address, 89 ) ([]byte, error) { 90 return b.CodeAt(ctx, account, new(big.Int).SetInt64(int64(rpc.PendingBlockNumber))) 91 } 92 93 func (b *EthAPIBackend) PendingNonceAt( 94 ctx context.Context, 95 account common.Address, 96 ) (uint64, error) { 97 return b.GetPoolNonce(ctx, account) 98 } 99 100 func (b *EthAPIBackend) PendingCallContract( 101 ctx context.Context, 102 call ethereum.CallMsg, 103 ) ([]byte, error) { 104 return b.CallContract(ctx, call, new(big.Int).SetInt64(int64(rpc.PendingBlockNumber))) 105 } 106 107 func (b *EthAPIBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) { 108 return b.gpo.SuggestPrice(ctx) 109 } 110 111 func (b *EthAPIBackend) EstimateGas( 112 ctx context.Context, 113 call ethereum.CallMsg, 114 ) (gas uint64, err error) { 115 return 0, errors.New("Not implemented") 116 } 117 118 func (b *EthAPIBackend) SendTransaction( 119 ctx context.Context, 120 tx *types.Transaction, 121 ) error { 122 return b.SendTx(ctx, tx) 123 } 124 125 // FilterLogs is a less efficient method of fetching the logs in a given block. 126 func (b *EthAPIBackend) FilterLogs( 127 ctx context.Context, 128 query ethereum.FilterQuery, 129 ) ([]types.Log, error) { 130 toBlock := rpc.LatestBlockNumber 131 if query.ToBlock != nil { 132 toBlock = rpc.BlockNumber(query.ToBlock.Int64()) 133 } 134 135 rpcBlockNumber := toBlock 136 if query.FromBlock != nil { 137 rpcBlockNumber = rpc.BlockNumber(query.FromBlock.Int64()) 138 } 139 140 requiredLogs := make([]types.Log, 0, int(toBlock-rpcBlockNumber)) 141 for i := rpcBlockNumber; i <= toBlock; i++ { 142 header, err := b.HeaderByNumber(ctx, i) 143 if err != nil { 144 return nil, err 145 } 146 147 // Fetch txs in the block with the provided block hash 148 allLogs, err := b.GetLogs(ctx, header.Hash()) 149 if err != nil { 150 return nil, err 151 } 152 153 blockNo := uint64(i) 154 for _, logs := range allLogs { 155 for _, log := range logs { 156 if b.isFilteredLog(ctx, query, log, &blockNo) { 157 requiredLogs = append(requiredLogs, *log) 158 } 159 } 160 } 161 162 // When fetching the latest block, do not loop more than once 163 if i == rpc.LatestBlockNumber { 164 break 165 } 166 } 167 168 return requiredLogs, nil 169 } 170 171 // SubscribeFilterLogs returns the logs that are created after subscription. 172 func (b *EthAPIBackend) SubscribeFilterLogs( 173 ctx context.Context, 174 query ethereum.FilterQuery, 175 ch chan<- types.Log, 176 ) (ethereum.Subscription, error) { 177 // Subscribe to all contract events 178 sinkLogs := make(chan []*types.Log) 179 180 sub := b.SubscribeLogsEvent(sinkLogs) 181 // Since we're getting logs in batches, we need to flatten them into a plain stream 182 return event.NewSubscription(func(quit <-chan struct{}) error { 183 defer sub.Unsubscribe() 184 for { 185 select { 186 case logs := <-sinkLogs: 187 for _, log := range logs { 188 // Select the required logs only. 189 if !b.isFilteredLog(ctx, query, log, nil) { 190 continue 191 } 192 193 select { 194 case ch <- *log: 195 case err := <-sub.Err(): 196 if err != nil { 197 return err 198 } 199 case <-quit: 200 return nil 201 } 202 } 203 case err := <-sub.Err(): 204 if err != nil { 205 return err 206 } 207 case <-quit: 208 return nil 209 } 210 } 211 }), nil 212 } 213 214 func (b *EthAPIBackend) isFilteredLog( 215 ctx context.Context, 216 q ethereum.FilterQuery, 217 log *types.Log, 218 blockNo *uint64, 219 ) bool { 220 221 for _, addr := range q.Addresses { 222 generalProxyHash := energi_common.GeneralProxyHashExtractor(ctx, addr, blockNo) 223 if generalProxyHash != nil && log.Address.Hash() == *generalProxyHash { 224 return true 225 } 226 227 if addr == log.Address { 228 return true 229 } 230 } 231 232 return false 233 }