This commit is contained in:
baizhenxuan 2017-11-13 14:05:45 +00:00 committed by GitHub
commit 54572c7b6d
8 changed files with 111 additions and 2 deletions

View file

@ -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.

View file

@ -41,6 +41,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.
@ -287,6 +288,15 @@ 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
}
// JumpTimeInSeconds adds skip seconds to the clock // JumpTimeInSeconds adds skip seconds to the clock
func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error { func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error {
b.mu.Lock() b.mu.Lock()

View file

@ -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

View file

@ -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

View file

@ -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}}
` `

View file

@ -20,6 +20,7 @@ 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"
@ -136,3 +137,11 @@ 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") //todo fix this need ethapi.Backend to modify and PublicFilterAPI export Logs func for local call.
}
func (b *ContractBackend) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]*types.Log, error) {
return nil, errors.New("not support right now")
}

View file

@ -349,8 +349,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
} }

View file

@ -66,6 +66,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
} }