mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-16 17:03:46 +00:00
accounts/abi: add event binding for go language
This commit is contained in:
parent
33cf1c74f2
commit
735f074c08
8 changed files with 121 additions and 2 deletions
|
|
@ -50,6 +50,10 @@ type ContractCaller interface {
|
|||
// ContractCall executes an Ethereum contract call with the specified data as the
|
||||
// input.
|
||||
CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error)
|
||||
// SubscribeFilterLogs subscribes to the results of a streaming filter query.
|
||||
SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error)
|
||||
// FilterLogs executes a filter query.
|
||||
FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]*types.Log, error)
|
||||
}
|
||||
|
||||
// DeployBackend wraps the operations needed by WaitMined and WaitDeployed.
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import (
|
|||
var _ bind.ContractBackend = (*SimulatedBackend)(nil)
|
||||
|
||||
var errBlockNumberUnsupported = errors.New("SimulatedBackend cannot access blocks other than the latest block")
|
||||
var errLogsUnsupported = errors.New("SimulatedBackend cannot query logs")
|
||||
|
||||
// SimulatedBackend implements bind.ContractBackend, simulating a blockchain in
|
||||
// the background. Its main purpose is to allow easily testing contract bindings.
|
||||
|
|
@ -284,6 +285,16 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
|
|||
return nil
|
||||
}
|
||||
|
||||
//cannot query logs on simulated blockchain
|
||||
func (b *SimulatedBackend) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) {
|
||||
return nil, errLogsUnsupported
|
||||
}
|
||||
|
||||
//cannot query logs on simulated blockchain
|
||||
func (b *SimulatedBackend) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]*types.Log, error) {
|
||||
return nil, errLogsUnsupported
|
||||
}
|
||||
|
||||
// callmsg implements core.Message to allow passing it as a transaction simulator.
|
||||
type callmsg struct {
|
||||
ethereum.CallMsg
|
||||
|
|
|
|||
|
|
@ -145,6 +145,33 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string,
|
|||
return c.abi.Unpack(result, method, output)
|
||||
}
|
||||
|
||||
// SubscribeFilterLogs query logs on blockchain with q.
|
||||
// it returns a channel which tell all the already happed logs and the logs that will happen.
|
||||
// you can cancel listen logs by Subscription's Unsubscribe
|
||||
func (c *BoundContract) SubscribeFilterLogs(opts *CallOpts, q ethereum.FilterQuery) (<-chan types.Log, ethereum.Subscription, error) {
|
||||
if opts == nil {
|
||||
opts = new(CallOpts)
|
||||
}
|
||||
var ctx = ensureContext(opts.Context)
|
||||
q.Addresses = []common.Address{c.address}
|
||||
//first get all happened logs on the blockchain.
|
||||
logs, err := c.caller.FilterLogs(ctx, q)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var ch = make(chan types.Log, len(logs))
|
||||
//subcribe logs that will happen.
|
||||
sub, err := c.caller.SubscribeFilterLogs(ctx, q, ch)
|
||||
if err != nil {
|
||||
close(ch)
|
||||
return nil, nil, err
|
||||
}
|
||||
for _, log := range logs {
|
||||
ch <- *log
|
||||
}
|
||||
return ch, sub, err
|
||||
}
|
||||
|
||||
// Transact invokes the (paid) contract method with params as input values.
|
||||
func (c *BoundContract) Transact(opts *TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||
// Otherwise pack up the parameters and invoke the contract
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string, lang La
|
|||
var (
|
||||
calls = make(map[string]*tmplMethod)
|
||||
transacts = make(map[string]*tmplMethod)
|
||||
events = make(map[string]string)
|
||||
)
|
||||
for _, original := range evmABI.Methods {
|
||||
// Normalize the method for capital cases and non-anonymous inputs/outputs
|
||||
|
|
@ -94,6 +95,9 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string, lang La
|
|||
transacts[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original)}
|
||||
}
|
||||
}
|
||||
for _, ev := range evmABI.Events {
|
||||
events[ev.Name] = ev.Name
|
||||
}
|
||||
contracts[types[i]] = &tmplContract{
|
||||
Type: capitalise(types[i]),
|
||||
InputABI: strings.Replace(strippedABI, "\"", "\\\"", -1),
|
||||
|
|
@ -101,6 +105,7 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string, lang La
|
|||
Constructor: evmABI.Constructor,
|
||||
Calls: calls,
|
||||
Transacts: transacts,
|
||||
Events: events,
|
||||
}
|
||||
}
|
||||
// Generate the contract template data content and render it
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ type tmplContract struct {
|
|||
Constructor abi.Method // Contract constructor for deploy parametrization
|
||||
Calls map[string]*tmplMethod // Contract calls that only read state data
|
||||
Transacts map[string]*tmplMethod // Contract calls that write state data
|
||||
Events map[string]string //all contract events except the anonymous events todo events's indexed argument information should be used to generate code.
|
||||
}
|
||||
|
||||
// tmplMethod is a wrapper around an abi.Method that contains a few preprocessed
|
||||
|
|
@ -263,6 +264,56 @@ package {{.Package}}
|
|||
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
{{end}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Caller) EventSubscribe(opts *bind.CallOpts, fromBlock rpc.BlockNumber,
|
||||
toBlock rpc.BlockNumber, eventName string) (<-chan types.Log, ethereum.Subscription, error) {
|
||||
parsed, err := abi.JSON(strings.NewReader(MyTokenABI))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var q ethereum.FilterQuery
|
||||
q.FromBlock = big.NewInt(int64(fromBlock))
|
||||
if toBlock == rpc.LatestBlockNumber {
|
||||
q.ToBlock = nil
|
||||
} else {
|
||||
q.ToBlock = big.NewInt(int64(toBlock))
|
||||
}
|
||||
q.Topics = [][]common.Hash{
|
||||
{parsed.Events[eventName].Id()}, //event signature
|
||||
}
|
||||
return _{{$contract.Type}}.contract.SubscribeFilterLogs(opts, q)
|
||||
}
|
||||
|
||||
{{range $name,$value := .Events}}
|
||||
/*
|
||||
get all event {{$name}} happened from [fromBlock] to [toBlock]
|
||||
if [toBlock] is -1, you can get all the events that will happen later.
|
||||
you can cancel event listenging through Subscription's Unsubscribe
|
||||
*/
|
||||
func (t *{{$contract.Type}}Caller) Event{{$name}}Subscribe(opts *bind.CallOpts, fromBlock rpc.BlockNumber,
|
||||
toBlock rpc.BlockNumber) (<-chan types.Log, ethereum.Subscription, error) {
|
||||
return t.EventSubscribe(opts, fromBlock, toBlock, "{{$name}}")
|
||||
}
|
||||
|
||||
/*
|
||||
get all event {{$name}} happened from [fromBlock] to [toBlock]
|
||||
if [toBlock] is -1, you can get all the events that will happen later.
|
||||
you can cancel event listenging through Subscription's Unsubscribe
|
||||
*/
|
||||
func (t *{{$contract.Type}}Session) Event{{$name}}Subscribe(fromBlock rpc.BlockNumber,
|
||||
toBlock rpc.BlockNumber) (<-chan types.Log, ethereum.Subscription, error) {
|
||||
return t.Contract.Event{{$name}}Subscribe(&t.CallOpts, fromBlock, toBlock)
|
||||
}
|
||||
|
||||
/*
|
||||
get all event {{$name}} happened from [fromBlock] to [toBlock]
|
||||
if [toBlock] is -1, you can get all the events that will happen later.
|
||||
you can cancel event listenging through Subscription's Unsubscribe
|
||||
*/
|
||||
func (t *{{$contract.Type}}CallerSession) Event{{$name}}Subscribe(opts *bind.CallOpts, fromBlock rpc.BlockNumber,
|
||||
toBlock rpc.BlockNumber) (<-chan types.Log, ethereum.Subscription, error) {
|
||||
return t.Contract.Event{{$name}}Subscribe(&t.CallOpts, fromBlock, toBlock)
|
||||
}
|
||||
{{end}}
|
||||
{{end}}
|
||||
`
|
||||
|
||||
|
|
|
|||
18
eth/bind.go
18
eth/bind.go
|
|
@ -20,10 +20,12 @@ import (
|
|||
"context"
|
||||
"math/big"
|
||||
|
||||
"errors"
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/eth/filters"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
|
|
@ -40,6 +42,7 @@ type ContractBackend struct {
|
|||
eapi *ethapi.PublicEthereumAPI // Wrapper around the Ethereum object to access metadata
|
||||
bcapi *ethapi.PublicBlockChainAPI // Wrapper around the blockchain to access chain data
|
||||
txapi *ethapi.PublicTransactionPoolAPI // Wrapper around the transaction pool to access transaction data
|
||||
fapi *filters.PublicFilterAPI //wrapper around the filter to filter logs
|
||||
}
|
||||
|
||||
// NewContractBackend creates a new native contract backend using an existing
|
||||
|
|
@ -49,6 +52,7 @@ func NewContractBackend(apiBackend ethapi.Backend) *ContractBackend {
|
|||
eapi: ethapi.NewPublicEthereumAPI(apiBackend),
|
||||
bcapi: ethapi.NewPublicBlockChainAPI(apiBackend),
|
||||
txapi: ethapi.NewPublicTransactionPoolAPI(apiBackend, new(ethapi.AddrLocker)),
|
||||
fapi: filters.NewPublicFilterAPI(apiBackend, false),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -136,3 +140,17 @@ func (b *ContractBackend) SendTransaction(ctx context.Context, tx *types.Transac
|
|||
_, err := b.txapi.SendRawTransaction(ctx, raw)
|
||||
return err
|
||||
}
|
||||
|
||||
func (b *ContractBackend) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) {
|
||||
return nil, errors.New("not support right now")
|
||||
}
|
||||
|
||||
func (b *ContractBackend) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]*types.Log, error) {
|
||||
crit := filters.FilterCriteria{
|
||||
FromBlock: q.FromBlock,
|
||||
ToBlock: q.ToBlock,
|
||||
Addresses: q.Addresses,
|
||||
Topics: q.Topics,
|
||||
}
|
||||
return b.fapi.GetLogs(ctx, crit)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -304,8 +304,8 @@ func (ec *Client) NonceAt(ctx context.Context, account common.Address, blockNumb
|
|||
// Filters
|
||||
|
||||
// FilterLogs executes a filter query.
|
||||
func (ec *Client) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) {
|
||||
var result []types.Log
|
||||
func (ec *Client) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]*types.Log, error) {
|
||||
var result []*types.Log
|
||||
err := ec.c.CallContext(ctx, &result, "eth_getLogs", toFilterArg(q))
|
||||
return result, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,9 @@ type Backend interface {
|
|||
TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions)
|
||||
SubscribeTxPreEvent(chan<- core.TxPreEvent) event.Subscription
|
||||
|
||||
SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription
|
||||
SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription
|
||||
|
||||
ChainConfig() *params.ChainConfig
|
||||
CurrentBlock() *types.Block
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue