mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
Merge fab8333bd2 into 6566a0a3b8
This commit is contained in:
commit
5cc42a3307
10 changed files with 330 additions and 135 deletions
|
|
@ -319,6 +319,21 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getBlockHash returns the block hash of the requested block.
|
||||||
|
// `hash` is used if supplied; if not the canonoical block at `number` is looked up.
|
||||||
|
// If neither is supplied, the latest canonical block hash is returned.
|
||||||
|
func (b *SimulatedBackend) getBlockHash(number *big.Int, hash *common.Hash) (common.Hash, error) {
|
||||||
|
if hash != nil {
|
||||||
|
return *hash, nil
|
||||||
|
} else if number != nil {
|
||||||
|
header := b.blockchain.GetHeaderByNumber(number.Uint64())
|
||||||
|
return header.Hash(), nil
|
||||||
|
} else {
|
||||||
|
header := b.blockchain.CurrentHeader()
|
||||||
|
return header.Hash(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FilterLogs executes a log filter operation, blocking during execution and
|
// FilterLogs executes a log filter operation, blocking during execution and
|
||||||
// returning all the results in one batch.
|
// returning all the results in one batch.
|
||||||
//
|
//
|
||||||
|
|
@ -330,13 +345,13 @@ func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.Filter
|
||||||
filter = filters.NewBlockFilter(&filterBackend{b.database, b.blockchain}, *query.BlockHash, query.Addresses, query.Topics)
|
filter = filters.NewBlockFilter(&filterBackend{b.database, b.blockchain}, *query.BlockHash, query.Addresses, query.Topics)
|
||||||
} else {
|
} else {
|
||||||
// Initialize unset filter boundaried to run from genesis to chain head
|
// Initialize unset filter boundaried to run from genesis to chain head
|
||||||
from := int64(0)
|
from, err := b.getBlockHash(query.FromBlock, query.FromBlockHash)
|
||||||
if query.FromBlock != nil {
|
if err != nil {
|
||||||
from = query.FromBlock.Int64()
|
return nil, err
|
||||||
}
|
}
|
||||||
to := int64(-1)
|
to, err := b.getBlockHash(query.ToBlock, query.ToBlockHash)
|
||||||
if query.ToBlock != nil {
|
if err != nil {
|
||||||
to = query.ToBlock.Int64()
|
return nil, err
|
||||||
}
|
}
|
||||||
// Construct the range filter
|
// Construct the range filter
|
||||||
filter = filters.NewRangeFilter(&filterBackend{b.database, b.blockchain}, from, to, query.Addresses, query.Topics)
|
filter = filters.NewRangeFilter(&filterBackend{b.database, b.blockchain}, from, to, query.Addresses, query.Topics)
|
||||||
|
|
|
||||||
|
|
@ -320,6 +320,27 @@ func (api *PublicFilterAPI) NewFilter(crit FilterCriteria) (rpc.ID, error) {
|
||||||
return logsSub.ID, nil
|
return logsSub.ID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getBlockHash returns the block hash of the requested block.
|
||||||
|
// `hash` is used if supplied; if not the canonoical block at `number` is looked up.
|
||||||
|
// If neither is supplied, the latest canonical block hash is returned.
|
||||||
|
func (api *PublicFilterAPI) getBlockHash(ctx context.Context, number *big.Int, hash *common.Hash) (common.Hash, error) {
|
||||||
|
if hash != nil {
|
||||||
|
return *hash, nil
|
||||||
|
} else if number != nil {
|
||||||
|
header, err := api.backend.HeaderByNumber(ctx, rpc.BlockNumber(number.Int64()))
|
||||||
|
if err != nil {
|
||||||
|
return common.Hash{}, err
|
||||||
|
}
|
||||||
|
return header.Hash(), nil
|
||||||
|
} else {
|
||||||
|
header, err := api.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber)
|
||||||
|
if err != nil {
|
||||||
|
return common.Hash{}, err
|
||||||
|
}
|
||||||
|
return header.Hash(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetLogs returns logs matching the given argument that are stored within the state.
|
// GetLogs returns logs matching the given argument that are stored within the state.
|
||||||
//
|
//
|
||||||
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs
|
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs
|
||||||
|
|
@ -329,14 +350,13 @@ func (api *PublicFilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([
|
||||||
// Block filter requested, construct a single-shot filter
|
// Block filter requested, construct a single-shot filter
|
||||||
filter = NewBlockFilter(api.backend, *crit.BlockHash, crit.Addresses, crit.Topics)
|
filter = NewBlockFilter(api.backend, *crit.BlockHash, crit.Addresses, crit.Topics)
|
||||||
} else {
|
} else {
|
||||||
// Convert the RPC block numbers into internal representations
|
begin, err := api.getBlockHash(ctx, crit.FromBlock, crit.FromBlockHash)
|
||||||
begin := rpc.LatestBlockNumber.Int64()
|
if err != nil {
|
||||||
if crit.FromBlock != nil {
|
return nil, err
|
||||||
begin = crit.FromBlock.Int64()
|
|
||||||
}
|
}
|
||||||
end := rpc.LatestBlockNumber.Int64()
|
end, err := api.getBlockHash(ctx, crit.ToBlock, crit.ToBlockHash)
|
||||||
if crit.ToBlock != nil {
|
if err != nil {
|
||||||
end = crit.ToBlock.Int64()
|
return nil, err
|
||||||
}
|
}
|
||||||
// Construct the range filter
|
// Construct the range filter
|
||||||
filter = NewRangeFilter(api.backend, begin, end, crit.Addresses, crit.Topics)
|
filter = NewRangeFilter(api.backend, begin, end, crit.Addresses, crit.Topics)
|
||||||
|
|
@ -384,14 +404,13 @@ func (api *PublicFilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]*ty
|
||||||
// Block filter requested, construct a single-shot filter
|
// Block filter requested, construct a single-shot filter
|
||||||
filter = NewBlockFilter(api.backend, *f.crit.BlockHash, f.crit.Addresses, f.crit.Topics)
|
filter = NewBlockFilter(api.backend, *f.crit.BlockHash, f.crit.Addresses, f.crit.Topics)
|
||||||
} else {
|
} else {
|
||||||
// Convert the RPC block numbers into internal representations
|
begin, err := api.getBlockHash(ctx, f.crit.FromBlock, f.crit.FromBlockHash)
|
||||||
begin := rpc.LatestBlockNumber.Int64()
|
if err != nil {
|
||||||
if f.crit.FromBlock != nil {
|
return nil, err
|
||||||
begin = f.crit.FromBlock.Int64()
|
|
||||||
}
|
}
|
||||||
end := rpc.LatestBlockNumber.Int64()
|
end, err := api.getBlockHash(ctx, f.crit.ToBlock, f.crit.ToBlockHash)
|
||||||
if f.crit.ToBlock != nil {
|
if err != nil {
|
||||||
end = f.crit.ToBlock.Int64()
|
return nil, err
|
||||||
}
|
}
|
||||||
// Construct the range filter
|
// Construct the range filter
|
||||||
filter = NewRangeFilter(api.backend, begin, end, f.crit.Addresses, f.crit.Topics)
|
filter = NewRangeFilter(api.backend, begin, end, f.crit.Addresses, f.crit.Topics)
|
||||||
|
|
@ -459,11 +478,11 @@ func returnLogs(logs []*types.Log) []*types.Log {
|
||||||
// UnmarshalJSON sets *args fields with given data.
|
// UnmarshalJSON sets *args fields with given data.
|
||||||
func (args *FilterCriteria) UnmarshalJSON(data []byte) error {
|
func (args *FilterCriteria) UnmarshalJSON(data []byte) error {
|
||||||
type input struct {
|
type input struct {
|
||||||
BlockHash *common.Hash `json:"blockHash"`
|
BlockHash *common.Hash `json:"blockHash"`
|
||||||
FromBlock *rpc.BlockNumber `json:"fromBlock"`
|
FromBlock *rpc.BlockNumberOrHash `json:"fromBlock"`
|
||||||
ToBlock *rpc.BlockNumber `json:"toBlock"`
|
ToBlock *rpc.BlockNumberOrHash `json:"toBlock"`
|
||||||
Addresses interface{} `json:"address"`
|
Addresses interface{} `json:"address"`
|
||||||
Topics []interface{} `json:"topics"`
|
Topics []interface{} `json:"topics"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var raw input
|
var raw input
|
||||||
|
|
@ -479,11 +498,18 @@ func (args *FilterCriteria) UnmarshalJSON(data []byte) error {
|
||||||
args.BlockHash = raw.BlockHash
|
args.BlockHash = raw.BlockHash
|
||||||
} else {
|
} else {
|
||||||
if raw.FromBlock != nil {
|
if raw.FromBlock != nil {
|
||||||
args.FromBlock = big.NewInt(raw.FromBlock.Int64())
|
if raw.FromBlock.IsHash() {
|
||||||
|
args.FromBlockHash = raw.FromBlock.Hash()
|
||||||
|
} else {
|
||||||
|
args.FromBlock = big.NewInt(int64(raw.FromBlock.Number()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if raw.ToBlock != nil {
|
if raw.ToBlock != nil {
|
||||||
args.ToBlock = big.NewInt(raw.ToBlock.Int64())
|
if raw.ToBlock.IsHash() {
|
||||||
|
args.ToBlockHash = raw.ToBlock.Hash()
|
||||||
|
} else {
|
||||||
|
args.ToBlock = big.NewInt(int64(raw.ToBlock.Number()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,13 +27,15 @@ import (
|
||||||
|
|
||||||
func TestUnmarshalJSONNewFilterArgs(t *testing.T) {
|
func TestUnmarshalJSONNewFilterArgs(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
fromBlock rpc.BlockNumber = 0x123435
|
fromBlock rpc.BlockNumber = 0x123435
|
||||||
toBlock rpc.BlockNumber = 0xabcdef
|
toBlock rpc.BlockNumber = 0xabcdef
|
||||||
address0 = common.HexToAddress("70c87d191324e6712a591f304b4eedef6ad9bb9d")
|
fromBlockHash = common.HexToHash("ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1ca3")
|
||||||
address1 = common.HexToAddress("9b2055d370f73ec7d8a03e965129118dc8f5bf83")
|
toBlockHash = common.HexToHash("084a792d2f8b16a62b882fd56f7860c07bf5fa91dd8a2ae7e809e5180fef0b39")
|
||||||
topic0 = common.HexToHash("3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1ca")
|
address0 = common.HexToAddress("70c87d191324e6712a591f304b4eedef6ad9bb9d")
|
||||||
topic1 = common.HexToHash("9084a792d2f8b16a62b882fd56f7860c07bf5fa91dd8a2ae7e809e5180fef0b3")
|
address1 = common.HexToAddress("9b2055d370f73ec7d8a03e965129118dc8f5bf83")
|
||||||
topic2 = common.HexToHash("6ccae1c4af4152f460ff510e573399795dfab5dcf1fa60d1f33ac8fdc1e480ce")
|
topic0 = common.HexToHash("3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1ca")
|
||||||
|
topic1 = common.HexToHash("9084a792d2f8b16a62b882fd56f7860c07bf5fa91dd8a2ae7e809e5180fef0b3")
|
||||||
|
topic2 = common.HexToHash("6ccae1c4af4152f460ff510e573399795dfab5dcf1fa60d1f33ac8fdc1e480ce")
|
||||||
)
|
)
|
||||||
|
|
||||||
// default values
|
// default values
|
||||||
|
|
@ -182,4 +184,17 @@ func TestUnmarshalJSONNewFilterArgs(t *testing.T) {
|
||||||
if len(test7.Topics[2]) != 0 {
|
if len(test7.Topics[2]) != 0 {
|
||||||
t.Fatalf("expected 0 topics, got %d topics", len(test7.Topics[2]))
|
t.Fatalf("expected 0 topics, got %d topics", len(test7.Topics[2]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// from, to block hash
|
||||||
|
var test8 FilterCriteria
|
||||||
|
vector = fmt.Sprintf(`{"fromBlock":"%s","toBlock":"%s"}`, fromBlockHash.Hex(), toBlockHash.Hex())
|
||||||
|
if err := json.Unmarshal([]byte(vector), &test8); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if *test8.FromBlockHash != fromBlockHash {
|
||||||
|
t.Fatalf("expected FromBlock %s, got %s", fromBlockHash.Hex(), test8.FromBlockHash.Hex())
|
||||||
|
}
|
||||||
|
if *test8.ToBlockHash != toBlockHash {
|
||||||
|
t.Fatalf("expected ToBlock %s, got %s", toBlockHash.Hex(), test8.ToBlockHash.Hex())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,8 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) {
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
end := rawdb.ReadCanonicalHash(db, uint64(cnt*sectionSize-1))
|
||||||
|
|
||||||
d := time.Since(start)
|
d := time.Since(start)
|
||||||
fmt.Println("Finished generating bloombits data")
|
fmt.Println("Finished generating bloombits data")
|
||||||
fmt.Println(" ", d, "total ", d/time.Duration(cnt*sectionSize), "per block")
|
fmt.Println(" ", d, "total ", d/time.Duration(cnt*sectionSize), "per block")
|
||||||
|
|
@ -135,7 +137,7 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) {
|
||||||
var addr common.Address
|
var addr common.Address
|
||||||
addr[0] = byte(i)
|
addr[0] = byte(i)
|
||||||
addr[1] = byte(i / 256)
|
addr[1] = byte(i / 256)
|
||||||
filter := NewRangeFilter(backend, 0, int64(cnt*sectionSize-1), []common.Address{addr}, nil)
|
filter := NewRangeFilter(backend, head, end, []common.Address{addr}, nil)
|
||||||
if _, err := filter.Logs(context.Background()); err != nil {
|
if _, err := filter.Logs(context.Background()); err != nil {
|
||||||
b.Error("filter.Find error:", err)
|
b.Error("filter.Find error:", err)
|
||||||
}
|
}
|
||||||
|
|
@ -192,7 +194,7 @@ func BenchmarkNoBloomBits(b *testing.B) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
mux := new(event.TypeMux)
|
mux := new(event.TypeMux)
|
||||||
backend := &testBackend{mux, db, 0, new(event.Feed), new(event.Feed), new(event.Feed), new(event.Feed)}
|
backend := &testBackend{mux, db, 0, new(event.Feed), new(event.Feed), new(event.Feed), new(event.Feed)}
|
||||||
filter := NewRangeFilter(backend, 0, int64(*headNum), []common.Address{{}}, nil)
|
filter := NewRangeFilter(backend, rawdb.ReadCanonicalHash(db, 0), head, []common.Address{{}}, nil)
|
||||||
filter.Logs(context.Background())
|
filter.Logs(context.Background())
|
||||||
d := time.Since(start)
|
d := time.Since(start)
|
||||||
fmt.Println("Finished running filter benchmarks")
|
fmt.Println("Finished running filter benchmarks")
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"sort"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
|
@ -56,14 +57,14 @@ type Filter struct {
|
||||||
topics [][]common.Hash
|
topics [][]common.Hash
|
||||||
|
|
||||||
block common.Hash // Block hash if filtering a single block
|
block common.Hash // Block hash if filtering a single block
|
||||||
begin, end int64 // Range interval if filtering multiple blocks
|
begin, end common.Hash // Range interval if filtering multiple blocks
|
||||||
|
|
||||||
matcher *bloombits.Matcher
|
matcher *bloombits.Matcher
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRangeFilter creates a new filter which uses a bloom filter on blocks to
|
// NewRangeFilter creates a new filter which uses a bloom filter on blocks to
|
||||||
// figure out whether a particular block is interesting or not.
|
// figure out whether a particular block is interesting or not.
|
||||||
func NewRangeFilter(backend Backend, begin, end int64, addresses []common.Address, topics [][]common.Hash) *Filter {
|
func NewRangeFilter(backend Backend, begin, end common.Hash, addresses []common.Address, topics [][]common.Hash) *Filter {
|
||||||
// Flatten the address and topic filter clauses into a single bloombits filter
|
// Flatten the address and topic filter clauses into a single bloombits filter
|
||||||
// system. Since the bloombits are not positional, nil topics are permitted,
|
// system. Since the bloombits are not positional, nil topics are permitted,
|
||||||
// which get flattened into a nil byte slice.
|
// which get flattened into a nil byte slice.
|
||||||
|
|
@ -114,9 +115,61 @@ func newFilter(backend Backend, addresses []common.Address, topics [][]common.Ha
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// findCommonAncestor returns the highest numbered block that is the ancestor of
|
||||||
|
// both `begin` and `end`. `end` must have a block number greater than or equal
|
||||||
|
// to `begin`.
|
||||||
|
func (f *Filter) findCommonAncestor(ctx context.Context, begin, end *types.Header) (*types.Header, bool, error) {
|
||||||
|
var err error
|
||||||
|
var mainChain bool
|
||||||
|
|
||||||
|
// If end is on the canonical chain, we can rewind efficiently
|
||||||
|
if header, err := f.backend.HeaderByNumber(ctx, rpc.BlockNumber(end.Number.Int64())); err != nil && header.Hash() == end.Hash() {
|
||||||
|
mainChain = true
|
||||||
|
end, err = f.backend.HeaderByNumber(ctx, rpc.BlockNumber(begin.Number.Int64()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mainChain = false
|
||||||
|
// Rewind until begin and end are at the same height
|
||||||
|
for end.Number.Cmp(begin.Number) > 0 {
|
||||||
|
end, err = f.backend.HeaderByHash(ctx, end.ParentHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rewind both until they match
|
||||||
|
for begin.Hash() != end.Hash() {
|
||||||
|
begin, err = f.backend.HeaderByHash(ctx, begin.ParentHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
end, err = f.backend.HeaderByHash(ctx, end.ParentHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return end, mainChain, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// logList allows sorting event logs by block number and log index
|
||||||
|
type logList []*types.Log
|
||||||
|
|
||||||
|
func (l logList) Len() int { return len(l) }
|
||||||
|
func (l logList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
|
||||||
|
func (l logList) Less(i, j int) bool {
|
||||||
|
return l[i].BlockNumber < l[j].BlockNumber || (l[i].BlockNumber == l[j].BlockNumber && l[i].Index < l[j].Index)
|
||||||
|
}
|
||||||
|
|
||||||
// Logs searches the blockchain for matching log entries, returning all from the
|
// Logs searches the blockchain for matching log entries, returning all from the
|
||||||
// first block that contains matches, updating the start of the filter accordingly.
|
// first block that contains matches, updating the start of the filter accordingly.
|
||||||
func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) {
|
func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
// If we're doing singleton block filtering, execute and return
|
// If we're doing singleton block filtering, execute and return
|
||||||
if f.block != (common.Hash{}) {
|
if f.block != (common.Hash{}) {
|
||||||
header, err := f.backend.HeaderByHash(ctx, f.block)
|
header, err := f.backend.HeaderByHash(ctx, f.block)
|
||||||
|
|
@ -128,48 +181,78 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) {
|
||||||
}
|
}
|
||||||
return f.blockLogs(ctx, header)
|
return f.blockLogs(ctx, header)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Figure out the limits of the filter range
|
// Figure out the limits of the filter range
|
||||||
header, _ := f.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber)
|
header, _ := f.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber)
|
||||||
if header == nil {
|
if header == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
head := header.Number.Uint64()
|
|
||||||
|
|
||||||
if f.begin == -1 {
|
begin := header
|
||||||
f.begin = int64(head)
|
if f.begin != (common.Hash{}) {
|
||||||
}
|
begin, err = f.backend.HeaderByHash(ctx, f.begin)
|
||||||
end := uint64(f.end)
|
|
||||||
if f.end == -1 {
|
|
||||||
end = head
|
|
||||||
}
|
|
||||||
// Gather all indexed logs, and finish with non indexed ones
|
|
||||||
var (
|
|
||||||
logs []*types.Log
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
size, sections := f.backend.BloomStatus()
|
|
||||||
if indexed := sections * size; indexed > uint64(f.begin) {
|
|
||||||
if indexed > end {
|
|
||||||
logs, err = f.indexedLogs(ctx, end)
|
|
||||||
} else {
|
|
||||||
logs, err = f.indexedLogs(ctx, indexed-1)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return logs, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rest, err := f.unindexedLogs(ctx, end)
|
|
||||||
|
end := header
|
||||||
|
if f.end != (common.Hash{}) {
|
||||||
|
end, err = f.backend.HeaderByHash(ctx, f.end)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if end.Number.Cmp(begin.Number) < 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ancestor, mainChain, err := f.findCommonAncestor(ctx, begin, end)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert deletions of any reorg-ed logs
|
||||||
|
var logs []*types.Log
|
||||||
|
removed, err := f.unindexedLogs(ctx, ancestor.Hash(), begin.Hash())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, log := range removed {
|
||||||
|
log.Removed = true
|
||||||
|
logs = append(logs, log)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gather all indexed logs, and finish with non indexed ones
|
||||||
|
if mainChain {
|
||||||
|
size, sections := f.backend.BloomStatus()
|
||||||
|
if indexed := sections * size; indexed > ancestor.Number.Uint64() {
|
||||||
|
if indexed > end.Number.Uint64() {
|
||||||
|
logs, err = f.indexedLogs(ctx, ancestor.Number.Uint64(), end.Number.Uint64())
|
||||||
|
} else {
|
||||||
|
logs, err = f.indexedLogs(ctx, ancestor.Number.Uint64(), indexed-1)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return logs, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rest, err := f.unindexedLogs(ctx, ancestor.Hash(), end.Hash())
|
||||||
logs = append(logs, rest...)
|
logs = append(logs, rest...)
|
||||||
|
sort.Sort(logList(logs))
|
||||||
|
|
||||||
|
f.begin = end.Hash()
|
||||||
return logs, err
|
return logs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// indexedLogs returns the logs matching the filter criteria based on the bloom
|
// indexedLogs returns the logs matching the filter criteria based on the bloom
|
||||||
// bits indexed available locally or via the network.
|
// bits indexed available locally or via the network.
|
||||||
func (f *Filter) indexedLogs(ctx context.Context, end uint64) ([]*types.Log, error) {
|
func (f *Filter) indexedLogs(ctx context.Context, begin, end uint64) ([]*types.Log, error) {
|
||||||
// Create a matcher session and request servicing from the backend
|
// Create a matcher session and request servicing from the backend
|
||||||
matches := make(chan uint64, 64)
|
matches := make(chan uint64, 64)
|
||||||
|
|
||||||
session, err := f.matcher.Start(ctx, uint64(f.begin), end, matches)
|
session, err := f.matcher.Start(ctx, begin, end, matches)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -186,18 +269,15 @@ func (f *Filter) indexedLogs(ctx context.Context, end uint64) ([]*types.Log, err
|
||||||
// Abort if all matches have been fulfilled
|
// Abort if all matches have been fulfilled
|
||||||
if !ok {
|
if !ok {
|
||||||
err := session.Error()
|
err := session.Error()
|
||||||
if err == nil {
|
|
||||||
f.begin = int64(end) + 1
|
|
||||||
}
|
|
||||||
return logs, err
|
return logs, err
|
||||||
}
|
}
|
||||||
f.begin = int64(number) + 1
|
|
||||||
|
|
||||||
// Retrieve the suggested block and pull any truly matching logs
|
// Retrieve the suggested block and pull any truly matching logs
|
||||||
header, err := f.backend.HeaderByNumber(ctx, rpc.BlockNumber(number))
|
header, err := f.backend.HeaderByNumber(ctx, rpc.BlockNumber(number))
|
||||||
if header == nil || err != nil {
|
if header == nil || err != nil {
|
||||||
return logs, err
|
return logs, err
|
||||||
}
|
}
|
||||||
|
f.begin = header.Hash()
|
||||||
found, err := f.checkMatches(ctx, header)
|
found, err := f.checkMatches(ctx, header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return logs, err
|
return logs, err
|
||||||
|
|
@ -212,11 +292,11 @@ func (f *Filter) indexedLogs(ctx context.Context, end uint64) ([]*types.Log, err
|
||||||
|
|
||||||
// indexedLogs returns the logs matching the filter criteria based on raw block
|
// indexedLogs returns the logs matching the filter criteria based on raw block
|
||||||
// iteration and bloom matching.
|
// iteration and bloom matching.
|
||||||
func (f *Filter) unindexedLogs(ctx context.Context, end uint64) ([]*types.Log, error) {
|
func (f *Filter) unindexedLogs(ctx context.Context, begin, end common.Hash) ([]*types.Log, error) {
|
||||||
var logs []*types.Log
|
var logs []*types.Log
|
||||||
|
|
||||||
for ; f.begin <= int64(end); f.begin++ {
|
for {
|
||||||
header, err := f.backend.HeaderByNumber(ctx, rpc.BlockNumber(f.begin))
|
header, err := f.backend.HeaderByHash(ctx, end)
|
||||||
if header == nil || err != nil {
|
if header == nil || err != nil {
|
||||||
return logs, err
|
return logs, err
|
||||||
}
|
}
|
||||||
|
|
@ -225,6 +305,10 @@ func (f *Filter) unindexedLogs(ctx context.Context, end uint64) ([]*types.Log, e
|
||||||
return logs, err
|
return logs, err
|
||||||
}
|
}
|
||||||
logs = append(logs, found...)
|
logs = append(logs, found...)
|
||||||
|
if begin == end {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
end = header.ParentHash
|
||||||
}
|
}
|
||||||
return logs, nil
|
return logs, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ func BenchmarkFilters(b *testing.B) {
|
||||||
}
|
}
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
||||||
filter := NewRangeFilter(backend, 0, -1, []common.Address{addr1, addr2, addr3, addr4}, nil)
|
filter := NewRangeFilter(backend, genesis.Hash(), rawdb.ReadHeadBlockHash(db), []common.Address{addr1, addr2, addr3, addr4}, nil)
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
logs, _ := filter.Logs(context.Background())
|
logs, _ := filter.Logs(context.Background())
|
||||||
|
|
@ -175,14 +175,16 @@ func TestFilters(t *testing.T) {
|
||||||
rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), receipts[i])
|
rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), receipts[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
filter := NewRangeFilter(backend, 0, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}})
|
head := rawdb.ReadHeadBlockHash(db)
|
||||||
|
|
||||||
|
filter := NewRangeFilter(backend, genesis.Hash(), head, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}})
|
||||||
|
|
||||||
logs, _ := filter.Logs(context.Background())
|
logs, _ := filter.Logs(context.Background())
|
||||||
if len(logs) != 4 {
|
if len(logs) != 4 {
|
||||||
t.Error("expected 4 log, got", len(logs))
|
t.Error("expected 4 log, got", len(logs))
|
||||||
}
|
}
|
||||||
|
|
||||||
filter = NewRangeFilter(backend, 900, 999, []common.Address{addr}, [][]common.Hash{{hash3}})
|
filter = NewRangeFilter(backend, rawdb.ReadCanonicalHash(db, 900), rawdb.ReadCanonicalHash(db, 999), []common.Address{addr}, [][]common.Hash{{hash3}})
|
||||||
logs, _ = filter.Logs(context.Background())
|
logs, _ = filter.Logs(context.Background())
|
||||||
if len(logs) != 1 {
|
if len(logs) != 1 {
|
||||||
t.Error("expected 1 log, got", len(logs))
|
t.Error("expected 1 log, got", len(logs))
|
||||||
|
|
@ -191,7 +193,7 @@ func TestFilters(t *testing.T) {
|
||||||
t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0])
|
t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
filter = NewRangeFilter(backend, 990, -1, []common.Address{addr}, [][]common.Hash{{hash3}})
|
filter = NewRangeFilter(backend, rawdb.ReadCanonicalHash(db, 990), head, []common.Address{addr}, [][]common.Hash{{hash3}})
|
||||||
logs, _ = filter.Logs(context.Background())
|
logs, _ = filter.Logs(context.Background())
|
||||||
if len(logs) != 1 {
|
if len(logs) != 1 {
|
||||||
t.Error("expected 1 log, got", len(logs))
|
t.Error("expected 1 log, got", len(logs))
|
||||||
|
|
@ -200,7 +202,7 @@ func TestFilters(t *testing.T) {
|
||||||
t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0])
|
t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
filter = NewRangeFilter(backend, 1, 10, nil, [][]common.Hash{{hash1, hash2}})
|
filter = NewRangeFilter(backend, rawdb.ReadCanonicalHash(db, 1), rawdb.ReadCanonicalHash(db, 10), nil, [][]common.Hash{{hash1, hash2}})
|
||||||
|
|
||||||
logs, _ = filter.Logs(context.Background())
|
logs, _ = filter.Logs(context.Background())
|
||||||
if len(logs) != 2 {
|
if len(logs) != 2 {
|
||||||
|
|
@ -208,7 +210,7 @@ func TestFilters(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
failHash := common.BytesToHash([]byte("fail"))
|
failHash := common.BytesToHash([]byte("fail"))
|
||||||
filter = NewRangeFilter(backend, 0, -1, nil, [][]common.Hash{{failHash}})
|
filter = NewRangeFilter(backend, genesis.Hash(), head, nil, [][]common.Hash{{failHash}})
|
||||||
|
|
||||||
logs, _ = filter.Logs(context.Background())
|
logs, _ = filter.Logs(context.Background())
|
||||||
if len(logs) != 0 {
|
if len(logs) != 0 {
|
||||||
|
|
@ -216,14 +218,14 @@ func TestFilters(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
failAddr := common.BytesToAddress([]byte("failmenow"))
|
failAddr := common.BytesToAddress([]byte("failmenow"))
|
||||||
filter = NewRangeFilter(backend, 0, -1, []common.Address{failAddr}, nil)
|
filter = NewRangeFilter(backend, genesis.Hash(), head, []common.Address{failAddr}, nil)
|
||||||
|
|
||||||
logs, _ = filter.Logs(context.Background())
|
logs, _ = filter.Logs(context.Background())
|
||||||
if len(logs) != 0 {
|
if len(logs) != 0 {
|
||||||
t.Error("expected 0 log, got", len(logs))
|
t.Error("expected 0 log, got", len(logs))
|
||||||
}
|
}
|
||||||
|
|
||||||
filter = NewRangeFilter(backend, 0, -1, nil, [][]common.Hash{{failHash}, {hash1}})
|
filter = NewRangeFilter(backend, genesis.Hash(), head, nil, [][]common.Hash{{failHash}, {hash1}})
|
||||||
|
|
||||||
logs, _ = filter.Logs(context.Background())
|
logs, _ = filter.Logs(context.Background())
|
||||||
if len(logs) != 0 {
|
if len(logs) != 0 {
|
||||||
|
|
|
||||||
|
|
@ -131,10 +131,12 @@ type ContractCaller interface {
|
||||||
|
|
||||||
// FilterQuery contains options for contract log filtering.
|
// FilterQuery contains options for contract log filtering.
|
||||||
type FilterQuery struct {
|
type FilterQuery struct {
|
||||||
BlockHash *common.Hash // used by eth_getLogs, return logs only from block with this hash
|
BlockHash *common.Hash // used by eth_getLogs, return logs only from block with this hash
|
||||||
FromBlock *big.Int // beginning of the queried range, nil means genesis block
|
FromBlock *big.Int // beginning of the queried range, nil means genesis block
|
||||||
ToBlock *big.Int // end of the range, nil means latest block
|
FromBlockHash *common.Hash // beginning of the queried range, as a block hash
|
||||||
Addresses []common.Address // restricts matches to events created by specific contracts
|
ToBlock *big.Int // end of the range, nil means latest block
|
||||||
|
ToBlockHash *common.Hash // end of the range, as a block hash
|
||||||
|
Addresses []common.Address // restricts matches to events created by specific contracts
|
||||||
|
|
||||||
// The Topic list restricts matches to particular event topics. Each event has a list
|
// The Topic list restricts matches to particular event topics. Each event has a list
|
||||||
// of topics. Topics matches a prefix of that list. An empty element slice matches any
|
// of topics. Topics matches a prefix of that list. An empty element slice matches any
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1192,7 +1192,7 @@ module.exports = SolidityTypeInt;
|
||||||
You should have received a copy of the GNU Lesser General Public License
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* @file param.js
|
* @file param.js
|
||||||
* @author Marek Kotewicz <marek@ethdev.com>
|
* @author Marek Kotewicz <marek@ethdev.com>
|
||||||
* @date 2015
|
* @date 2015
|
||||||
|
|
@ -1211,7 +1211,7 @@ var SolidityParam = function (value, offset) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method should be used to get length of params's dynamic part
|
* This method should be used to get length of params's dynamic part
|
||||||
*
|
*
|
||||||
* @method dynamicPartLength
|
* @method dynamicPartLength
|
||||||
* @returns {Number} length of dynamic part (in bytes)
|
* @returns {Number} length of dynamic part (in bytes)
|
||||||
*/
|
*/
|
||||||
|
|
@ -1239,7 +1239,7 @@ SolidityParam.prototype.withOffset = function (offset) {
|
||||||
* @param {SolidityParam} result of combination
|
* @param {SolidityParam} result of combination
|
||||||
*/
|
*/
|
||||||
SolidityParam.prototype.combine = function (param) {
|
SolidityParam.prototype.combine = function (param) {
|
||||||
return new SolidityParam(this.value + param.value);
|
return new SolidityParam(this.value + param.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1271,8 +1271,8 @@ SolidityParam.prototype.offsetAsBytes = function () {
|
||||||
*/
|
*/
|
||||||
SolidityParam.prototype.staticPart = function () {
|
SolidityParam.prototype.staticPart = function () {
|
||||||
if (!this.isDynamic()) {
|
if (!this.isDynamic()) {
|
||||||
return this.value;
|
return this.value;
|
||||||
}
|
}
|
||||||
return this.offsetAsBytes();
|
return this.offsetAsBytes();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1304,7 +1304,7 @@ SolidityParam.prototype.encode = function () {
|
||||||
* @returns {String}
|
* @returns {String}
|
||||||
*/
|
*/
|
||||||
SolidityParam.encodeList = function (params) {
|
SolidityParam.encodeList = function (params) {
|
||||||
|
|
||||||
// updating offsets
|
// updating offsets
|
||||||
var totalOffset = params.length * 32;
|
var totalOffset = params.length * 32;
|
||||||
var offsetParams = params.map(function (param) {
|
var offsetParams = params.map(function (param) {
|
||||||
|
|
@ -1746,13 +1746,13 @@ if (typeof XMLHttpRequest === 'undefined') {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utils
|
* Utils
|
||||||
*
|
*
|
||||||
* @module utils
|
* @module utils
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility functions
|
* Utility functions
|
||||||
*
|
*
|
||||||
* @class [utils] config
|
* @class [utils] config
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
|
|
@ -1819,7 +1819,7 @@ module.exports = {
|
||||||
You should have received a copy of the GNU Lesser General Public License
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* @file sha3.js
|
* @file sha3.js
|
||||||
* @author Marek Kotewicz <marek@ethdev.com>
|
* @author Marek Kotewicz <marek@ethdev.com>
|
||||||
* @date 2015
|
* @date 2015
|
||||||
|
|
@ -2739,7 +2739,7 @@ module.exports = AllSolidityEvents;
|
||||||
You should have received a copy of the GNU Lesser General Public License
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* @file batch.js
|
* @file batch.js
|
||||||
* @author Marek Kotewicz <marek@ethdev.com>
|
* @author Marek Kotewicz <marek@ethdev.com>
|
||||||
* @date 2015
|
* @date 2015
|
||||||
|
|
@ -2784,7 +2784,7 @@ Batch.prototype.execute = function () {
|
||||||
requests[index].callback(null, (requests[index].format ? requests[index].format(result.result) : result.result));
|
requests[index].callback(null, (requests[index].format ? requests[index].format(result.result) : result.result));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Batch;
|
module.exports = Batch;
|
||||||
|
|
@ -2971,7 +2971,7 @@ var ContractFactory = function (eth, abi) {
|
||||||
*/
|
*/
|
||||||
this.new = function () {
|
this.new = function () {
|
||||||
/*jshint maxcomplexity: 7 */
|
/*jshint maxcomplexity: 7 */
|
||||||
|
|
||||||
var contract = new Contract(this.eth, this.abi);
|
var contract = new Contract(this.eth, this.abi);
|
||||||
|
|
||||||
// parse arguments
|
// parse arguments
|
||||||
|
|
@ -3119,7 +3119,7 @@ module.exports = ContractFactory;
|
||||||
You should have received a copy of the GNU Lesser General Public License
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* @file errors.js
|
* @file errors.js
|
||||||
* @author Marek Kotewicz <marek@ethdev.com>
|
* @author Marek Kotewicz <marek@ethdev.com>
|
||||||
* @date 2015
|
* @date 2015
|
||||||
|
|
@ -3394,7 +3394,7 @@ var extend = function (web3) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ex.formatters = formatters;
|
ex.formatters = formatters;
|
||||||
ex.utils = utils;
|
ex.utils = utils;
|
||||||
ex.Method = Method;
|
ex.Method = Method;
|
||||||
ex.Property = Property;
|
ex.Property = Property;
|
||||||
|
|
@ -4425,7 +4425,7 @@ module.exports = HttpProvider;
|
||||||
You should have received a copy of the GNU Lesser General Public License
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* @file iban.js
|
* @file iban.js
|
||||||
* @author Marek Kotewicz <marek@ethdev.com>
|
* @author Marek Kotewicz <marek@ethdev.com>
|
||||||
* @date 2015
|
* @date 2015
|
||||||
|
|
@ -4625,7 +4625,7 @@ Iban.prototype.address = function () {
|
||||||
var base36 = this._iban.substr(4);
|
var base36 = this._iban.substr(4);
|
||||||
var asBn = new BigNumber(base36, 36);
|
var asBn = new BigNumber(base36, 36);
|
||||||
return padLeft(asBn.toString(16), 20);
|
return padLeft(asBn.toString(16), 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
};
|
};
|
||||||
|
|
@ -4670,7 +4670,7 @@ var IpcProvider = function (path, net) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
this.responseCallbacks = {};
|
this.responseCallbacks = {};
|
||||||
this.path = path;
|
this.path = path;
|
||||||
|
|
||||||
this.connection = net.connect({path: this.path});
|
this.connection = net.connect({path: this.path});
|
||||||
|
|
||||||
this.connection.on('error', function(e){
|
this.connection.on('error', function(e){
|
||||||
|
|
@ -4680,7 +4680,7 @@ var IpcProvider = function (path, net) {
|
||||||
|
|
||||||
this.connection.on('end', function(){
|
this.connection.on('end', function(){
|
||||||
_this._timeout();
|
_this._timeout();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// LISTEN FOR CONNECTION RESPONSES
|
// LISTEN FOR CONNECTION RESPONSES
|
||||||
|
|
@ -4719,7 +4719,7 @@ Will parse the response and make an array out of it.
|
||||||
IpcProvider.prototype._parseResponse = function(data) {
|
IpcProvider.prototype._parseResponse = function(data) {
|
||||||
var _this = this,
|
var _this = this,
|
||||||
returnValues = [];
|
returnValues = [];
|
||||||
|
|
||||||
// DE-CHUNKER
|
// DE-CHUNKER
|
||||||
var dechunkedData = data
|
var dechunkedData = data
|
||||||
.replace(/\}[\n\r]?\{/g,'}|--|{') // }{
|
.replace(/\}[\n\r]?\{/g,'}|--|{') // }{
|
||||||
|
|
@ -4823,7 +4823,7 @@ IpcProvider.prototype.send = function (payload) {
|
||||||
try {
|
try {
|
||||||
result = JSON.parse(data);
|
result = JSON.parse(data);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
throw errors.InvalidResponse(data);
|
throw errors.InvalidResponse(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -4998,7 +4998,7 @@ Method.prototype.extractCallback = function (args) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should be called to check if the number of arguments is correct
|
* Should be called to check if the number of arguments is correct
|
||||||
*
|
*
|
||||||
* @method validateArgs
|
* @method validateArgs
|
||||||
* @param {Array} arguments
|
* @param {Array} arguments
|
||||||
* @throws {Error} if it is not
|
* @throws {Error} if it is not
|
||||||
|
|
@ -5011,7 +5011,7 @@ Method.prototype.validateArgs = function (args) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should be called to format input args of method
|
* Should be called to format input args of method
|
||||||
*
|
*
|
||||||
* @method formatInput
|
* @method formatInput
|
||||||
* @param {Array}
|
* @param {Array}
|
||||||
* @return {Array}
|
* @return {Array}
|
||||||
|
|
@ -5065,7 +5065,7 @@ Method.prototype.attachToObject = function (obj) {
|
||||||
obj[name[0]] = obj[name[0]] || {};
|
obj[name[0]] = obj[name[0]] || {};
|
||||||
obj[name[0]][name[1]] = func;
|
obj[name[0]][name[1]] = func;
|
||||||
} else {
|
} else {
|
||||||
obj[name[0]] = func;
|
obj[name[0]] = func;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -5128,8 +5128,8 @@ var DB = function (web3) {
|
||||||
this._requestManager = web3._requestManager;
|
this._requestManager = web3._requestManager;
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
methods().forEach(function(method) {
|
methods().forEach(function(method) {
|
||||||
method.attachToObject(self);
|
method.attachToObject(self);
|
||||||
method.setRequestManager(web3._requestManager);
|
method.setRequestManager(web3._requestManager);
|
||||||
});
|
});
|
||||||
|
|
@ -5431,6 +5431,12 @@ var methods = function () {
|
||||||
params: 0
|
params: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var getLogs = new Method({
|
||||||
|
name: 'getLogs',
|
||||||
|
call: 'eth_getLogs',
|
||||||
|
params: 1
|
||||||
|
})
|
||||||
|
|
||||||
return [
|
return [
|
||||||
getBalance,
|
getBalance,
|
||||||
getStorageAt,
|
getStorageAt,
|
||||||
|
|
@ -5454,7 +5460,8 @@ var methods = function () {
|
||||||
compileLLL,
|
compileLLL,
|
||||||
compileSerpent,
|
compileSerpent,
|
||||||
submitWork,
|
submitWork,
|
||||||
getWork
|
getWork,
|
||||||
|
getLogs
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -5554,7 +5561,7 @@ var Net = function (web3) {
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
properties().forEach(function(p) {
|
properties().forEach(function(p) {
|
||||||
p.attachToObject(self);
|
p.attachToObject(self);
|
||||||
p.setRequestManager(web3._requestManager);
|
p.setRequestManager(web3._requestManager);
|
||||||
});
|
});
|
||||||
|
|
@ -6113,7 +6120,7 @@ module.exports = {
|
||||||
You should have received a copy of the GNU Lesser General Public License
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* @file namereg.js
|
* @file namereg.js
|
||||||
* @author Marek Kotewicz <marek@ethdev.com>
|
* @author Marek Kotewicz <marek@ethdev.com>
|
||||||
* @date 2015
|
* @date 2015
|
||||||
|
|
@ -6300,7 +6307,7 @@ module.exports = Property;
|
||||||
You should have received a copy of the GNU Lesser General Public License
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* @file requestmanager.js
|
* @file requestmanager.js
|
||||||
* @author Jeffrey Wilcke <jeff@ethdev.com>
|
* @author Jeffrey Wilcke <jeff@ethdev.com>
|
||||||
* @author Marek Kotewicz <marek@ethdev.com>
|
* @author Marek Kotewicz <marek@ethdev.com>
|
||||||
|
|
@ -6367,7 +6374,7 @@ RequestManager.prototype.sendAsync = function (data, callback) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Jsonrpc.isValidResponse(result)) {
|
if (!Jsonrpc.isValidResponse(result)) {
|
||||||
return callback(errors.InvalidResponse(result));
|
return callback(errors.InvalidResponse(result));
|
||||||
}
|
}
|
||||||
|
|
@ -6400,7 +6407,7 @@ RequestManager.prototype.sendBatch = function (data, callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(err, results);
|
callback(err, results);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -6504,7 +6511,7 @@ RequestManager.prototype.poll = function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
var payload = Jsonrpc.toBatchPayload(pollsData);
|
var payload = Jsonrpc.toBatchPayload(pollsData);
|
||||||
|
|
||||||
// map the request id to they poll id
|
// map the request id to they poll id
|
||||||
var pollsIdMap = {};
|
var pollsIdMap = {};
|
||||||
payload.forEach(function(load, index){
|
payload.forEach(function(load, index){
|
||||||
|
|
@ -6534,7 +6541,7 @@ RequestManager.prototype.poll = function () {
|
||||||
} else
|
} else
|
||||||
return false;
|
return false;
|
||||||
}).filter(function (result) {
|
}).filter(function (result) {
|
||||||
return !!result;
|
return !!result;
|
||||||
}).filter(function (result) {
|
}).filter(function (result) {
|
||||||
var valid = Jsonrpc.isValidResponse(result);
|
var valid = Jsonrpc.isValidResponse(result);
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
|
|
@ -6609,16 +6616,16 @@ var pollSyncing = function(self) {
|
||||||
|
|
||||||
self.callbacks.forEach(function (callback) {
|
self.callbacks.forEach(function (callback) {
|
||||||
if (self.lastSyncState !== sync) {
|
if (self.lastSyncState !== sync) {
|
||||||
|
|
||||||
// call the callback with true first so the app can stop anything, before receiving the sync data
|
// call the callback with true first so the app can stop anything, before receiving the sync data
|
||||||
if(!self.lastSyncState && utils.isObject(sync))
|
if(!self.lastSyncState && utils.isObject(sync))
|
||||||
callback(null, true);
|
callback(null, true);
|
||||||
|
|
||||||
// call on the next CPU cycle, so the actions of the sync stop can be processes first
|
// call on the next CPU cycle, so the actions of the sync stop can be processes first
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
callback(null, sync);
|
callback(null, sync);
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
self.lastSyncState = sync;
|
self.lastSyncState = sync;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -6673,7 +6680,7 @@ module.exports = IsSyncing;
|
||||||
You should have received a copy of the GNU Lesser General Public License
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* @file transfer.js
|
* @file transfer.js
|
||||||
* @author Marek Kotewicz <marek@ethdev.com>
|
* @author Marek Kotewicz <marek@ethdev.com>
|
||||||
* @date 2015
|
* @date 2015
|
||||||
|
|
@ -6692,7 +6699,7 @@ var exchangeAbi = require('../contracts/SmartExchange.json');
|
||||||
* @param {Function} callback, callback
|
* @param {Function} callback, callback
|
||||||
*/
|
*/
|
||||||
var transfer = function (eth, from, to, value, callback) {
|
var transfer = function (eth, from, to, value, callback) {
|
||||||
var iban = new Iban(to);
|
var iban = new Iban(to);
|
||||||
if (!iban.isValid()) {
|
if (!iban.isValid()) {
|
||||||
throw new Error('invalid iban address');
|
throw new Error('invalid iban address');
|
||||||
}
|
}
|
||||||
|
|
@ -6700,7 +6707,7 @@ var transfer = function (eth, from, to, value, callback) {
|
||||||
if (iban.isDirect()) {
|
if (iban.isDirect()) {
|
||||||
return transferToAddress(eth, from, iban.address(), value, callback);
|
return transferToAddress(eth, from, iban.address(), value, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!callback) {
|
if (!callback) {
|
||||||
var address = eth.icapNamereg().addr(iban.institution());
|
var address = eth.icapNamereg().addr(iban.institution());
|
||||||
return deposit(eth, from, address, value, iban.client());
|
return deposit(eth, from, address, value, iban.client());
|
||||||
|
|
@ -6709,7 +6716,7 @@ var transfer = function (eth, from, to, value, callback) {
|
||||||
eth.icapNamereg().addr(iban.institution(), function (err, address) {
|
eth.icapNamereg().addr(iban.institution(), function (err, address) {
|
||||||
return deposit(eth, from, address, value, iban.client(), callback);
|
return deposit(eth, from, address, value, iban.client(), callback);
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
38
rpc/types.go
38
rpc/types.go
|
|
@ -20,10 +20,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
mapset "github.com/deckarep/golang-set"
|
mapset "github.com/deckarep/golang-set"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -134,6 +136,11 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error {
|
||||||
input := strings.TrimSpace(string(data))
|
input := strings.TrimSpace(string(data))
|
||||||
if len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' {
|
if len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' {
|
||||||
input = input[1 : len(input)-1]
|
input = input[1 : len(input)-1]
|
||||||
|
} else {
|
||||||
|
// Integer block number
|
||||||
|
value, err := strconv.Atoi(string(data))
|
||||||
|
*bn = BlockNumber(value)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch input {
|
switch input {
|
||||||
|
|
@ -163,3 +170,34 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error {
|
||||||
func (bn BlockNumber) Int64() int64 {
|
func (bn BlockNumber) Int64() int64 {
|
||||||
return (int64)(bn)
|
return (int64)(bn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BlockNumberOrHash permits JSON deserialization and parsing of a value that
|
||||||
|
// can be either a block number or block hash.
|
||||||
|
type BlockNumberOrHash string
|
||||||
|
|
||||||
|
// UnmarshalJSON parses the supplied JSON fragment as a BlockNumberOrHash.
|
||||||
|
func (bnh *BlockNumberOrHash) UnmarshalJSON(data []byte) error {
|
||||||
|
*bnh = BlockNumberOrHash(data)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsHash returns true iff the value is a block hash.
|
||||||
|
func (bnh BlockNumberOrHash) IsHash() bool {
|
||||||
|
return bnh[0] == '"' && bnh[len(bnh)-1] == '"' && len(bnh) == 68
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash returns the hash value, or nil if the value is not a hash.
|
||||||
|
func (bnh BlockNumberOrHash) Hash() *common.Hash {
|
||||||
|
if !bnh.IsHash() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
hash := common.HexToHash(string(bnh[1 : len(bnh)-1]))
|
||||||
|
return &hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number returns the numeric value, or 0 if the value is not numeric.
|
||||||
|
func (bnh BlockNumberOrHash) Number() int64 {
|
||||||
|
var bn BlockNumber
|
||||||
|
(&bn).UnmarshalJSON([]byte(bnh))
|
||||||
|
return bn.Int64()
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue