github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/accounts/abi/bind/backends/simulated.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //版权所有2015 Go Ethereum作者
    10  //此文件是Go以太坊库的一部分。
    11  //
    12  //Go-Ethereum库是免费软件:您可以重新分发它和/或修改
    13  //根据GNU发布的较低通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊图书馆的发行目的是希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU较低的通用公共许可证,了解更多详细信息。
    21  //
    22  //你应该收到一份GNU较低级别的公共许可证副本
    23  //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  package backends
    26  
    27  import (
    28  	"context"
    29  	"errors"
    30  	"fmt"
    31  	"math/big"
    32  	"sync"
    33  	"time"
    34  
    35  	"github.com/ethereum/go-ethereum"
    36  	"github.com/ethereum/go-ethereum/accounts/abi/bind"
    37  	"github.com/ethereum/go-ethereum/common"
    38  	"github.com/ethereum/go-ethereum/common/math"
    39  //“github.com/ethereum/go-ethereum/consultance/ethash”
    40  	"github.com/ethereum/go-ethereum/core"
    41  	"github.com/ethereum/go-ethereum/core/bloombits"
    42  	"github.com/ethereum/go-ethereum/core/rawdb"
    43  	"github.com/ethereum/go-ethereum/core/state"
    44  	"github.com/ethereum/go-ethereum/core/types"
    45  	"github.com/ethereum/go-ethereum/core/vm"
    46  	"github.com/ethereum/go-ethereum/eth/filters"
    47  	"github.com/ethereum/go-ethereum/ethdb"
    48  	"github.com/ethereum/go-ethereum/event"
    49  	"github.com/ethereum/go-ethereum/params"
    50  	"github.com/ethereum/go-ethereum/rpc"
    51  	"github.com/ethereum/go-ethereum/consensus/dpos"
    52  )
    53  //这个nil分配确保了模拟后端实现bind.contractbackend的编译时间。
    54  var _ bind.ContractBackend = (*SimulatedBackend)(nil)
    55  
    56  var errBlockNumberUnsupported = errors.New("SimulatedBackend cannot access blocks other than the latest block")
    57  var errGasEstimationFailed = errors.New("gas required exceeds allowance or always failing transaction")
    58  
    59  //Simulatedbackend实现bind.contractbackend,在
    60  //背景。其主要目的是允许轻松测试合同绑定。
    61  type SimulatedBackend struct {
    62  database   ethdb.Database   //存储测试数据的内存数据库
    63  blockchain *core.BlockChain //以太坊区块链处理共识
    64  
    65  	mu           sync.Mutex
    66  pendingBlock *types.Block   //将根据请求导入的当前挂起块
    67  pendingState *state.StateDB //当前处于挂起状态,根据请求将处于活动状态
    68  
    69  events *filters.EventSystem //用于实时筛选日志事件的事件系统
    70  
    71  	config *params.ChainConfig
    72  }
    73  
    74  //NewSimulatedBackend使用模拟区块链创建新的绑定后端
    75  //用于测试。
    76  func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend {
    77  	database := ethdb.NewMemDatabase()
    78  	genesis := core.Genesis{Config: params.DposChainConfig, Alloc: alloc}
    79  	genesis.MustCommit(database)
    80  	dposcfg := 	&params.DposConfig {
    81  		Validators: []common.Address{
    82  			common.HexToAddress("0x3645b2bc6febc23d6634cc4114627c2b57b7dbb596c1bbb26af7ed9c4e57f370"),
    83  			common.HexToAddress("0x7bf279be14c6928b0ae372f82016138a49e80a146853bc5de45ba30069ef58a9"),
    84  		},
    85  	}
    86  	blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, dpos.New(dposcfg ,database), vm.Config{})
    87  
    88  	backend := &SimulatedBackend{
    89  		database:   database,
    90  		blockchain: blockchain,
    91  		config:     genesis.Config,
    92  		events:     filters.NewEventSystem(new(event.TypeMux), &filterBackend{database, blockchain}, false),
    93  	}
    94  	backend.rollback()
    95  	return backend
    96  }
    97  
    98  //commit将所有挂起的事务作为单个块导入并启动
    99  //新的状态。
   100  func (b *SimulatedBackend) Commit() {
   101  	b.mu.Lock()
   102  	defer b.mu.Unlock()
   103  
   104  	if _, err := b.blockchain.InsertChain([]*types.Block{b.pendingBlock}); err != nil {
   105  panic(err) //除非模拟器出错,否则不会发生这种情况,在这种情况下会失败。
   106  	}
   107  	b.rollback()
   108  }
   109  
   110  //回滚将中止所有挂起的事务,恢复到上一次提交的状态。
   111  func (b *SimulatedBackend) Rollback() {
   112  	b.mu.Lock()
   113  	defer b.mu.Unlock()
   114  
   115  	b.rollback()
   116  }
   117  
   118  func (b *SimulatedBackend) rollback() {
   119  	blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(int, *core.BlockGen) {})
   120  	statedb, _ := b.blockchain.State()
   121  
   122  	b.pendingBlock = blocks[0]
   123  	b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database())
   124  }
   125  
   126  //codeat返回与区块链中某个帐户关联的代码。
   127  func (b *SimulatedBackend) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) {
   128  	b.mu.Lock()
   129  	defer b.mu.Unlock()
   130  
   131  	if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 {
   132  		return nil, errBlockNumberUnsupported
   133  	}
   134  	statedb, _ := b.blockchain.State()
   135  	return statedb.GetCode(contract), nil
   136  }
   137  
   138  //balanceat返回区块链中某个账户的wei余额。
   139  func (b *SimulatedBackend) BalanceAt(ctx context.Context, contract common.Address, blockNumber *big.Int) (*big.Int, error) {
   140  	b.mu.Lock()
   141  	defer b.mu.Unlock()
   142  
   143  	if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 {
   144  		return nil, errBlockNumberUnsupported
   145  	}
   146  	statedb, _ := b.blockchain.State()
   147  	return statedb.GetBalance(contract), nil
   148  }
   149  
   150  //nonceat返回区块链中某个帐户的nonce。
   151  func (b *SimulatedBackend) NonceAt(ctx context.Context, contract common.Address, blockNumber *big.Int) (uint64, error) {
   152  	b.mu.Lock()
   153  	defer b.mu.Unlock()
   154  
   155  	if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 {
   156  		return 0, errBlockNumberUnsupported
   157  	}
   158  	statedb, _ := b.blockchain.State()
   159  	return statedb.GetNonce(contract), nil
   160  }
   161  
   162  //storageat返回在区块链中存储帐户的密钥的值。
   163  func (b *SimulatedBackend) StorageAt(ctx context.Context, contract common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) {
   164  	b.mu.Lock()
   165  	defer b.mu.Unlock()
   166  
   167  	if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 {
   168  		return nil, errBlockNumberUnsupported
   169  	}
   170  	statedb, _ := b.blockchain.State()
   171  	val := statedb.GetState(contract, key)
   172  	return val[:], nil
   173  }
   174  
   175  //TransactionReceipt返回交易的收据。
   176  func (b *SimulatedBackend) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
   177  	receipt, _, _, _ := rawdb.ReadReceipt(b.database, txHash)
   178  	return receipt, nil
   179  }
   180  
   181  //PendingCodeAt返回与处于挂起状态的帐户关联的代码。
   182  func (b *SimulatedBackend) PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) {
   183  	b.mu.Lock()
   184  	defer b.mu.Unlock()
   185  
   186  	return b.pendingState.GetCode(contract), nil
   187  }
   188  
   189  //CallContract执行合同调用。
   190  func (b *SimulatedBackend) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
   191  	b.mu.Lock()
   192  	defer b.mu.Unlock()
   193  
   194  	if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 {
   195  		return nil, errBlockNumberUnsupported
   196  	}
   197  	state, err := b.blockchain.State()
   198  	if err != nil {
   199  		return nil, err
   200  	}
   201  	rval, _, _, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), state)
   202  	return rval, err
   203  }
   204  
   205  //PendingCallContract对挂起状态执行合同调用。
   206  func (b *SimulatedBackend) PendingCallContract(ctx context.Context, call ethereum.CallMsg) ([]byte, error) {
   207  	b.mu.Lock()
   208  	defer b.mu.Unlock()
   209  	defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot())
   210  
   211  	rval, _, _, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
   212  	return rval, err
   213  }
   214  
   215  //PendingOnCate实现PendingStateReader.PendingOnCate,检索
   216  //当前为帐户挂起的非现金。
   217  func (b *SimulatedBackend) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) {
   218  	b.mu.Lock()
   219  	defer b.mu.Unlock()
   220  
   221  	return b.pendingState.GetOrNewStateObject(account).Nonce(), nil
   222  }
   223  
   224  //Suggestgasprice执行ContractTransactor.Suggestgasprice。自从模拟
   225  //这家连锁店没有矿工,我们只要回电1美元的汽油价格就行了。
   226  func (b *SimulatedBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
   227  	return big.NewInt(1), nil
   228  }
   229  
   230  //EstimateGas针对当前挂起的块/状态执行请求的代码,并且
   231  //返回使用的气体量。
   232  func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) {
   233  	b.mu.Lock()
   234  	defer b.mu.Unlock()
   235  
   236  //确定二元搜索的最低和最高气体限制
   237  	var (
   238  		lo  uint64 = params.TxGas - 1
   239  		hi  uint64
   240  		cap uint64
   241  	)
   242  	if call.Gas >= params.TxGas {
   243  		hi = call.Gas
   244  	} else {
   245  		hi = b.pendingBlock.GasLimit()
   246  	}
   247  	cap = hi
   248  
   249  //创建一个助手以检查气体限额是否导致可执行事务
   250  	executable := func(gas uint64) bool {
   251  		call.Gas = gas
   252  
   253  		snapshot := b.pendingState.Snapshot()
   254  		_, _, failed, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
   255  		b.pendingState.RevertToSnapshot(snapshot)
   256  
   257  		if err != nil || failed {
   258  			return false
   259  		}
   260  		return true
   261  	}
   262  //执行二进制搜索并按可执行的气体限值接通。
   263  	for lo+1 < hi {
   264  		mid := (hi + lo) / 2
   265  		if !executable(mid) {
   266  			lo = mid
   267  		} else {
   268  			hi = mid
   269  		}
   270  	}
   271  //如果交易仍以最高限额失败,则将其视为无效拒绝交易
   272  	if hi == cap {
   273  		if !executable(hi) {
   274  			return 0, errGasEstimationFailed
   275  		}
   276  	}
   277  	return hi, nil
   278  }
   279  
   280  //CallContract实现正常和挂起的合同调用之间的公共代码。
   281  //状态在执行期间被修改,请确保在必要时复制它。
   282  func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, block *types.Block, statedb *state.StateDB) ([]byte, uint64, bool, error) {
   283  //确保消息已正确初始化。
   284  	if call.GasPrice == nil {
   285  		call.GasPrice = big.NewInt(1)
   286  	}
   287  	if call.Gas == 0 {
   288  		call.Gas = 50000000
   289  	}
   290  	if call.Value == nil {
   291  		call.Value = new(big.Int)
   292  	}
   293  //将无限余额设置为假呼叫者帐户。
   294  	from := statedb.GetOrNewStateObject(call.From)
   295  	from.SetBalance(math.MaxBig256)
   296  //执行呼叫。
   297  	msg := callmsg{call}
   298  
   299  	evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain, nil)
   300  //创建一个保存所有相关信息的新环境
   301  //关于事务和调用机制。
   302  	vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{})
   303  	gaspool := new(core.GasPool).AddGas(math.MaxUint64)
   304  
   305  	return core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
   306  }
   307  
   308  //sendTransaction更新挂起块以包括给定的事务。
   309  //如果事务无效,它会恐慌。
   310  func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error {
   311  	b.mu.Lock()
   312  	defer b.mu.Unlock()
   313  
   314  	sender, err := types.Sender(types.HomesteadSigner{}, tx)
   315  	if err != nil {
   316  		panic(fmt.Errorf("invalid transaction: %v", err))
   317  	}
   318  	nonce := b.pendingState.GetNonce(sender)
   319  	if tx.Nonce() != nonce {
   320  		panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce))
   321  	}
   322  
   323  	blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
   324  		for _, tx := range b.pendingBlock.Transactions() {
   325  			block.AddTxWithChain(b.blockchain, tx)
   326  		}
   327  		block.AddTxWithChain(b.blockchain, tx)
   328  	})
   329  	statedb, _ := b.blockchain.State()
   330  
   331  	b.pendingBlock = blocks[0]
   332  	b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database())
   333  	return nil
   334  }
   335  
   336  //filterlogs执行日志筛选操作,在执行期间阻塞,以及
   337  //一批返回所有结果。
   338  //
   339  //TODO(karalabe):当订阅可以返回过去的数据时,取消预测。
   340  func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) {
   341  	var filter *filters.Filter
   342  	if query.BlockHash != nil {
   343  //请求块筛选器,构造一个单镜头筛选器
   344  		filter = filters.NewBlockFilter(&filterBackend{b.database, b.blockchain}, *query.BlockHash, query.Addresses, query.Topics)
   345  	} else {
   346  //初始化从Genesis运行到链头的未设置过滤器
   347  		from := int64(0)
   348  		if query.FromBlock != nil {
   349  			from = query.FromBlock.Int64()
   350  		}
   351  		to := int64(-1)
   352  		if query.ToBlock != nil {
   353  			to = query.ToBlock.Int64()
   354  		}
   355  //构造范围过滤器
   356  		filter = filters.NewRangeFilter(&filterBackend{b.database, b.blockchain}, from, to, query.Addresses, query.Topics)
   357  	}
   358  //运行过滤器并返回所有日志
   359  	logs, err := filter.Logs(ctx)
   360  	if err != nil {
   361  		return nil, err
   362  	}
   363  	res := make([]types.Log, len(logs))
   364  	for i, log := range logs {
   365  		res[i] = *log
   366  	}
   367  	return res, nil
   368  }
   369  
   370  //subscribeBilterLogs创建后台日志筛选操作,返回
   371  //立即订阅,可用于流式处理找到的事件。
   372  func (b *SimulatedBackend) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) {
   373  //订阅合同事件
   374  	sink := make(chan []*types.Log)
   375  
   376  	sub, err := b.events.SubscribeLogs(query, sink)
   377  	if err != nil {
   378  		return nil, err
   379  	}
   380  //因为我们要批量获取日志,所以我们需要将它们展平成一条普通的流。
   381  	return event.NewSubscription(func(quit <-chan struct{}) error {
   382  		defer sub.Unsubscribe()
   383  		for {
   384  			select {
   385  			case logs := <-sink:
   386  				for _, log := range logs {
   387  					select {
   388  					case ch <- *log:
   389  					case err := <-sub.Err():
   390  						return err
   391  					case <-quit:
   392  						return nil
   393  					}
   394  				}
   395  			case err := <-sub.Err():
   396  				return err
   397  			case <-quit:
   398  				return nil
   399  			}
   400  		}
   401  	}), nil
   402  }
   403  
   404  //AdjustTime为模拟时钟增加了一个时间偏移。
   405  func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error {
   406  	b.mu.Lock()
   407  	defer b.mu.Unlock()
   408  	blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
   409  		for _, tx := range b.pendingBlock.Transactions() {
   410  			block.AddTx(tx)
   411  		}
   412  		block.OffsetTime(int64(adjustment.Seconds()))
   413  	})
   414  	statedb, _ := b.blockchain.State()
   415  
   416  	b.pendingBlock = blocks[0]
   417  	b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database())
   418  
   419  	return nil
   420  }
   421  
   422  //callmsg实现core.message以允许将其作为事务模拟器传递。
   423  type callmsg struct {
   424  	ethereum.CallMsg
   425  }
   426  
   427  func (m callmsg) From() common.Address { return m.CallMsg.From }
   428  func (m callmsg) Nonce() uint64        { return 0 }
   429  func (m callmsg) CheckNonce() bool     { return false }
   430  func (m callmsg) To() *common.Address  { return m.CallMsg.To }
   431  func (m callmsg) GasPrice() *big.Int   { return m.CallMsg.GasPrice }
   432  func (m callmsg) Gas() uint64          { return m.CallMsg.Gas }
   433  func (m callmsg) Value() *big.Int      { return m.CallMsg.Value }
   434  func (m callmsg) Data() []byte         { return m.CallMsg.Data }
   435  
   436  //filterbackend实现筛选器。backend支持筛选不包含
   437  //考虑到布卢姆钻头的加速结构。
   438  type filterBackend struct {
   439  	db ethdb.Database
   440  	bc *core.BlockChain
   441  }
   442  
   443  func (fb *filterBackend) ChainDb() ethdb.Database  { return fb.db }
   444  func (fb *filterBackend) EventMux() *event.TypeMux { panic("not supported") }
   445  
   446  func (fb *filterBackend) HeaderByNumber(ctx context.Context, block rpc.BlockNumber) (*types.Header, error) {
   447  	if block == rpc.LatestBlockNumber {
   448  		return fb.bc.CurrentHeader(), nil
   449  	}
   450  	return fb.bc.GetHeaderByNumber(uint64(block.Int64())), nil
   451  }
   452  
   453  func (fb *filterBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
   454  	return fb.bc.GetHeaderByHash(hash), nil
   455  }
   456  
   457  func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
   458  	number := rawdb.ReadHeaderNumber(fb.db, hash)
   459  	if number == nil {
   460  		return nil, nil
   461  	}
   462  	return rawdb.ReadReceipts(fb.db, hash, *number), nil
   463  }
   464  
   465  func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) {
   466  	number := rawdb.ReadHeaderNumber(fb.db, hash)
   467  	if number == nil {
   468  		return nil, nil
   469  	}
   470  	receipts := rawdb.ReadReceipts(fb.db, hash, *number)
   471  	if receipts == nil {
   472  		return nil, nil
   473  	}
   474  	logs := make([][]*types.Log, len(receipts))
   475  	for i, receipt := range receipts {
   476  		logs[i] = receipt.Logs
   477  	}
   478  	return logs, nil
   479  }
   480  
   481  func (fb *filterBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
   482  	return event.NewSubscription(func(quit <-chan struct{}) error {
   483  		<-quit
   484  		return nil
   485  	})
   486  }
   487  func (fb *filterBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
   488  	return fb.bc.SubscribeChainEvent(ch)
   489  }
   490  func (fb *filterBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
   491  	return fb.bc.SubscribeRemovedLogsEvent(ch)
   492  }
   493  func (fb *filterBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
   494  	return fb.bc.SubscribeLogsEvent(ch)
   495  }
   496  
   497  func (fb *filterBackend) BloomStatus() (uint64, uint64) { return 4096, 0 }
   498  func (fb *filterBackend) ServiceFilter(ctx context.Context, ms *bloombits.MatcherSession) {
   499  	panic("not supported")
   500  }