github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/accounts/abi/bind/base.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 bind 26 27 import ( 28 "context" 29 "errors" 30 "fmt" 31 "math/big" 32 33 "github.com/ethereum/go-ethereum" 34 "github.com/ethereum/go-ethereum/accounts/abi" 35 "github.com/ethereum/go-ethereum/common" 36 "github.com/ethereum/go-ethereum/core/types" 37 "github.com/ethereum/go-ethereum/crypto" 38 "github.com/ethereum/go-ethereum/event" 39 ) 40 41 //当约定要求方法 42 //提交前签署交易。 43 type SignerFn func(types.Signer, common.Address, *types.Transaction) (*types.Transaction, error) 44 45 //Callopts是对合同调用请求进行微调的选项集合。 46 type CallOpts struct { 47 Pending bool //是否对挂起状态或最后一个已知状态进行操作 48 From common.Address //可选发件人地址,否则使用第一个帐户 49 50 Context context.Context //支持取消和超时的网络上下文(nil=无超时) 51 } 52 53 //TransactioOpts是创建 54 //有效的以太坊事务。 55 type TransactOpts struct { 56 From common.Address //用于发送交易的以太坊帐户 57 Nonce *big.Int //nonce用于事务执行(nil=使用挂起状态) 58 Signer SignerFn //用于签署交易的方法(强制) 59 60 Value *big.Int //随交易转移的资金(零=0=无资金) 61 GasPrice *big.Int //用于交易执行的天然气价格(零=天然气价格Oracle) 62 GasLimit uint64 //为交易执行设定的气体限制(0=估计) 63 64 Context context.Context //支持取消和超时的网络上下文(nil=无超时) 65 } 66 67 //filteropts是用于微调事件筛选的选项集合。 68 //在有约束力的合同中。 69 type FilterOpts struct { 70 Start uint64 //查询范围的开始 71 End *uint64 //范围结束(零=最新) 72 73 Context context.Context //支持取消和超时的网络上下文(nil=无超时) 74 } 75 76 //watchopts是对事件订阅进行微调的选项集合。 77 //在有约束力的合同中。 78 type WatchOpts struct { 79 Start *uint64 //查询范围的开始(nil=最新) 80 Context context.Context //支持取消和超时的网络上下文(nil=无超时) 81 } 82 83 //BoundContract是反映在 84 //以太坊网络。它包含由 85 //要操作的更高级别合同绑定。 86 type BoundContract struct { 87 address common.Address //以太坊区块链上合同的部署地址 88 abi abi.ABI //基于反射的ABI访问正确的以太坊方法 89 caller ContractCaller //读取与区块链交互的界面 90 transactor ContractTransactor //编写与区块链交互的接口 91 filterer ContractFilterer //与区块链交互的事件过滤 92 } 93 94 //NewboundContract创建一个低级合同接口,通过它调用 95 //交易可以通过。 96 func NewBoundContract(address common.Address, abi abi.ABI, caller ContractCaller, transactor ContractTransactor, filterer ContractFilterer) *BoundContract { 97 return &BoundContract{ 98 address: address, 99 abi: abi, 100 caller: caller, 101 transactor: transactor, 102 filterer: filterer, 103 } 104 } 105 106 //DeployContract将合同部署到以太坊区块链上,并绑定 107 //使用Go包装器的部署地址。 108 func DeployContract(opts *TransactOpts, abi abi.ABI, bytecode []byte, backend ContractBackend, params ...interface{}) (common.Address, *types.Transaction, *BoundContract, error) { 109 //否则,尝试部署合同 110 c := NewBoundContract(common.Address{}, abi, backend, backend, backend) 111 112 input, err := c.abi.Pack("", params...) 113 if err != nil { 114 return common.Address{}, nil, nil, err 115 } 116 tx, err := c.transact(opts, nil, append(bytecode, input...)) 117 if err != nil { 118 return common.Address{}, nil, nil, err 119 } 120 c.address = crypto.CreateAddress(opts.From, tx.Nonce()) 121 return c.address, tx, c, nil 122 } 123 124 //调用调用(常量)contract方法,参数作为输入值,并且 125 //将输出设置为结果。结果类型可能是用于 126 //返回、匿名返回的接口切片和命名的结构 127 //返回。 128 func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string, params ...interface{}) error { 129 //不要在懒惰的用户身上崩溃 130 if opts == nil { 131 opts = new(CallOpts) 132 } 133 //打包输入,调用并解压缩结果 134 input, err := c.abi.Pack(method, params...) 135 if err != nil { 136 return err 137 } 138 var ( 139 msg = ethereum.CallMsg{From: opts.From, To: &c.address, Data: input} 140 ctx = ensureContext(opts.Context) 141 code []byte 142 output []byte 143 ) 144 if opts.Pending { 145 pb, ok := c.caller.(PendingContractCaller) 146 if !ok { 147 return ErrNoPendingState 148 } 149 output, err = pb.PendingCallContract(ctx, msg) 150 if err == nil && len(output) == 0 { 151 //确保我们有一份合同要执行,否则就要保释。 152 if code, err = pb.PendingCodeAt(ctx, c.address); err != nil { 153 return err 154 } else if len(code) == 0 { 155 return ErrNoCode 156 } 157 } 158 } else { 159 output, err = c.caller.CallContract(ctx, msg, nil) 160 if err == nil && len(output) == 0 { 161 //确保我们有一份合同要执行,否则就要保释。 162 if code, err = c.caller.CodeAt(ctx, c.address, nil); err != nil { 163 return err 164 } else if len(code) == 0 { 165 return ErrNoCode 166 } 167 } 168 } 169 if err != nil { 170 return err 171 } 172 return c.abi.Unpack(result, method, output) 173 } 174 175 //Transact使用参数作为输入值调用(付费)Contract方法。 176 func (c *BoundContract) Transact(opts *TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { 177 //否则,打包参数并调用合同 178 input, err := c.abi.Pack(method, params...) 179 if err != nil { 180 return nil, err 181 } 182 return c.transact(opts, &c.address, input) 183 } 184 185 //转账启动普通交易以将资金转移到合同,调用 186 //它的默认方法(如果有)。 187 func (c *BoundContract) Transfer(opts *TransactOpts) (*types.Transaction, error) { 188 return c.transact(opts, &c.address, nil) 189 } 190 191 //Transact执行实际的事务调用,首先派生任何缺少的 192 //授权字段,然后安排事务执行。 193 func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, input []byte) (*types.Transaction, error) { 194 var err error 195 196 //确保有效的值字段并立即解析帐户 197 value := opts.Value 198 if value == nil { 199 value = new(big.Int) 200 } 201 var nonce uint64 202 if opts.Nonce == nil { 203 nonce, err = c.transactor.PendingNonceAt(ensureContext(opts.Context), opts.From) 204 if err != nil { 205 return nil, fmt.Errorf("failed to retrieve account nonce: %v", err) 206 } 207 } else { 208 nonce = opts.Nonce.Uint64() 209 } 210 //计算燃气补贴和燃气价格 211 gasPrice := opts.GasPrice 212 if gasPrice == nil { 213 gasPrice, err = c.transactor.SuggestGasPrice(ensureContext(opts.Context)) 214 if err != nil { 215 return nil, fmt.Errorf("failed to suggest gas price: %v", err) 216 } 217 } 218 gasLimit := opts.GasLimit 219 if gasLimit == 0 { 220 //如果没有方法调用代码,则无法成功估计气体 221 if contract != nil { 222 if code, err := c.transactor.PendingCodeAt(ensureContext(opts.Context), c.address); err != nil { 223 return nil, err 224 } else if len(code) == 0 { 225 return nil, ErrNoCode 226 } 227 } 228 //如果合同确实有代码(或不需要代码),则估计交易 229 msg := ethereum.CallMsg{From: opts.From, To: contract, Value: value, Data: input} 230 gasLimit, err = c.transactor.EstimateGas(ensureContext(opts.Context), msg) 231 if err != nil { 232 return nil, fmt.Errorf("failed to estimate gas needed: %v", err) 233 } 234 } 235 //创建事务,签名并计划执行 236 var rawTx *types.Transaction 237 if contract == nil { 238 rawTx = types.NewContractCreation(nonce, value, gasLimit, gasPrice, input) 239 } else { 240 rawTx = types.NewTransaction(nonce, c.address, value, gasLimit, gasPrice, input) 241 } 242 if opts.Signer == nil { 243 return nil, errors.New("no signer to authorize the transaction with") 244 } 245 signedTx, err := opts.Signer(types.HomesteadSigner{}, opts.From, rawTx) 246 if err != nil { 247 return nil, err 248 } 249 if err := c.transactor.SendTransaction(ensureContext(opts.Context), signedTx); err != nil { 250 return nil, err 251 } 252 return signedTx, nil 253 } 254 255 //filterlogs过滤过去块的合同日志,返回必要的 256 //在其上构造强类型绑定迭代器的通道。 257 func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]interface{}) (chan types.Log, event.Subscription, error) { 258 //不要在懒惰的用户身上崩溃 259 if opts == nil { 260 opts = new(FilterOpts) 261 } 262 //将事件选择器附加到查询参数并构造主题集 263 query = append([][]interface{}{{c.abi.Events[name].Id()}}, query...) 264 265 topics, err := makeTopics(query...) 266 if err != nil { 267 return nil, nil, err 268 } 269 //启动后台筛选 270 logs := make(chan types.Log, 128) 271 272 config := ethereum.FilterQuery{ 273 Addresses: []common.Address{c.address}, 274 Topics: topics, 275 FromBlock: new(big.Int).SetUint64(opts.Start), 276 } 277 if opts.End != nil { 278 config.ToBlock = new(big.Int).SetUint64(*opts.End) 279 } 280 /*TODO(karalabe):在支持时用此替换下面方法的其余部分 281 sub,err:=c.filter.subscribeBilterLogs(ensureContext(opts.context)、config、logs) 282 **/ 283 284 buff, err := c.filterer.FilterLogs(ensureContext(opts.Context), config) 285 if err != nil { 286 return nil, nil, err 287 } 288 sub, err := event.NewSubscription(func(quit <-chan struct{}) error { 289 for _, log := range buff { 290 select { 291 case logs <- log: 292 case <-quit: 293 return nil 294 } 295 } 296 return nil 297 }), nil 298 299 if err != nil { 300 return nil, nil, err 301 } 302 return logs, sub, nil 303 } 304 305 //watchlogs过滤器订阅未来块的合同日志,返回 306 //可用于关闭观察程序的订阅对象。 307 func (c *BoundContract) WatchLogs(opts *WatchOpts, name string, query ...[]interface{}) (chan types.Log, event.Subscription, error) { 308 //不要在懒惰的用户身上崩溃 309 if opts == nil { 310 opts = new(WatchOpts) 311 } 312 //将事件选择器附加到查询参数并构造主题集 313 query = append([][]interface{}{{c.abi.Events[name].Id()}}, query...) 314 315 topics, err := makeTopics(query...) 316 if err != nil { 317 return nil, nil, err 318 } 319 //启动后台筛选 320 logs := make(chan types.Log, 128) 321 322 config := ethereum.FilterQuery{ 323 Addresses: []common.Address{c.address}, 324 Topics: topics, 325 } 326 if opts.Start != nil { 327 config.FromBlock = new(big.Int).SetUint64(*opts.Start) 328 } 329 sub, err := c.filterer.SubscribeFilterLogs(ensureContext(opts.Context), config, logs) 330 if err != nil { 331 return nil, nil, err 332 } 333 return logs, sub, nil 334 } 335 336 //解包日志将检索到的日志解包到提供的输出结构中。 337 func (c *BoundContract) UnpackLog(out interface{}, event string, log types.Log) error { 338 if len(log.Data) > 0 { 339 if err := c.abi.Unpack(out, event, log.Data); err != nil { 340 return err 341 } 342 } 343 var indexed abi.Arguments 344 for _, arg := range c.abi.Events[event].Inputs { 345 if arg.Indexed { 346 indexed = append(indexed, arg) 347 } 348 } 349 return parseTopics(out, indexed, log.Topics[1:]) 350 } 351 352 //EnsureContext是一个助手方法,用于确保上下文不为零,即使 353 //用户指定了它。 354 func ensureContext(ctx context.Context) context.Context { 355 if ctx == nil { 356 return context.TODO() 357 } 358 return ctx 359 }