mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-17 09:23:48 +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
|
// ContractCall executes an Ethereum contract call with the specified data as the
|
||||||
// input.
|
// input.
|
||||||
CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error)
|
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.
|
// DeployBackend wraps the operations needed by WaitMined and WaitDeployed.
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ import (
|
||||||
var _ bind.ContractBackend = (*SimulatedBackend)(nil)
|
var _ bind.ContractBackend = (*SimulatedBackend)(nil)
|
||||||
|
|
||||||
var errBlockNumberUnsupported = errors.New("SimulatedBackend cannot access blocks other than the latest block")
|
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
|
// SimulatedBackend implements bind.ContractBackend, simulating a blockchain in
|
||||||
// the background. Its main purpose is to allow easily testing contract bindings.
|
// 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
|
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.
|
// callmsg implements core.Message to allow passing it as a transaction simulator.
|
||||||
type callmsg struct {
|
type callmsg struct {
|
||||||
ethereum.CallMsg
|
ethereum.CallMsg
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,33 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string,
|
||||||
return c.abi.Unpack(result, method, output)
|
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.
|
// Transact invokes the (paid) contract method with params as input values.
|
||||||
func (c *BoundContract) Transact(opts *TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
func (c *BoundContract) Transact(opts *TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||||
// Otherwise pack up the parameters and invoke the contract
|
// 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 (
|
var (
|
||||||
calls = make(map[string]*tmplMethod)
|
calls = make(map[string]*tmplMethod)
|
||||||
transacts = make(map[string]*tmplMethod)
|
transacts = make(map[string]*tmplMethod)
|
||||||
|
events = make(map[string]string)
|
||||||
)
|
)
|
||||||
for _, original := range evmABI.Methods {
|
for _, original := range evmABI.Methods {
|
||||||
// Normalize the method for capital cases and non-anonymous inputs/outputs
|
// 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)}
|
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{
|
contracts[types[i]] = &tmplContract{
|
||||||
Type: capitalise(types[i]),
|
Type: capitalise(types[i]),
|
||||||
InputABI: strings.Replace(strippedABI, "\"", "\\\"", -1),
|
InputABI: strings.Replace(strippedABI, "\"", "\\\"", -1),
|
||||||
|
|
@ -101,6 +105,7 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string, lang La
|
||||||
Constructor: evmABI.Constructor,
|
Constructor: evmABI.Constructor,
|
||||||
Calls: calls,
|
Calls: calls,
|
||||||
Transacts: transacts,
|
Transacts: transacts,
|
||||||
|
Events: events,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Generate the contract template data content and render it
|
// Generate the contract template data content and render it
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ type tmplContract struct {
|
||||||
Constructor abi.Method // Contract constructor for deploy parametrization
|
Constructor abi.Method // Contract constructor for deploy parametrization
|
||||||
Calls map[string]*tmplMethod // Contract calls that only read state data
|
Calls map[string]*tmplMethod // Contract calls that only read state data
|
||||||
Transacts map[string]*tmplMethod // Contract calls that write 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
|
// 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}})
|
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||||
}
|
}
|
||||||
{{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}}
|
{{end}}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
||||||
18
eth/bind.go
18
eth/bind.go
|
|
@ -20,10 +20,12 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
"errors"
|
||||||
"github.com/ethereum/go-ethereum"
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"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/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
|
@ -40,6 +42,7 @@ type ContractBackend struct {
|
||||||
eapi *ethapi.PublicEthereumAPI // Wrapper around the Ethereum object to access metadata
|
eapi *ethapi.PublicEthereumAPI // Wrapper around the Ethereum object to access metadata
|
||||||
bcapi *ethapi.PublicBlockChainAPI // Wrapper around the blockchain to access chain data
|
bcapi *ethapi.PublicBlockChainAPI // Wrapper around the blockchain to access chain data
|
||||||
txapi *ethapi.PublicTransactionPoolAPI // Wrapper around the transaction pool to access transaction 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
|
// NewContractBackend creates a new native contract backend using an existing
|
||||||
|
|
@ -49,6 +52,7 @@ func NewContractBackend(apiBackend ethapi.Backend) *ContractBackend {
|
||||||
eapi: ethapi.NewPublicEthereumAPI(apiBackend),
|
eapi: ethapi.NewPublicEthereumAPI(apiBackend),
|
||||||
bcapi: ethapi.NewPublicBlockChainAPI(apiBackend),
|
bcapi: ethapi.NewPublicBlockChainAPI(apiBackend),
|
||||||
txapi: ethapi.NewPublicTransactionPoolAPI(apiBackend, new(ethapi.AddrLocker)),
|
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)
|
_, err := b.txapi.SendRawTransaction(ctx, raw)
|
||||||
return err
|
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
|
// Filters
|
||||||
|
|
||||||
// FilterLogs executes a filter query.
|
// FilterLogs executes a filter query.
|
||||||
func (ec *Client) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) {
|
func (ec *Client) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]*types.Log, error) {
|
||||||
var result []types.Log
|
var result []*types.Log
|
||||||
err := ec.c.CallContext(ctx, &result, "eth_getLogs", toFilterArg(q))
|
err := ec.c.CallContext(ctx, &result, "eth_getLogs", toFilterArg(q))
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,9 @@ type Backend interface {
|
||||||
TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions)
|
TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions)
|
||||||
SubscribeTxPreEvent(chan<- core.TxPreEvent) event.Subscription
|
SubscribeTxPreEvent(chan<- core.TxPreEvent) event.Subscription
|
||||||
|
|
||||||
|
SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription
|
||||||
|
SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription
|
||||||
|
|
||||||
ChainConfig() *params.ChainConfig
|
ChainConfig() *params.ChainConfig
|
||||||
CurrentBlock() *types.Block
|
CurrentBlock() *types.Block
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue