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  }