eth/filters: fix a breaking change and return rpctransaction (#26757)
* eth/filters: fix a breaking change and return rpctransaction * eth/filters: fix test cases --------- Co-authored-by: Catror <me@catror.com>
This commit is contained in:
parent
fe01a2f63b
commit
4034c675be
@ -39,6 +39,7 @@ type filter struct {
|
|||||||
typ Type
|
typ Type
|
||||||
deadline *time.Timer // filter is inactive when deadline triggers
|
deadline *time.Timer // filter is inactive when deadline triggers
|
||||||
hashes []common.Hash
|
hashes []common.Hash
|
||||||
|
fullTx bool
|
||||||
txs []*types.Transaction
|
txs []*types.Transaction
|
||||||
crit FilterCriteria
|
crit FilterCriteria
|
||||||
logs []*types.Log
|
logs []*types.Log
|
||||||
@ -103,14 +104,14 @@ func (api *FilterAPI) timeoutLoop(timeout time.Duration) {
|
|||||||
//
|
//
|
||||||
// It is part of the filter package because this filter can be used through the
|
// It is part of the filter package because this filter can be used through the
|
||||||
// `eth_getFilterChanges` polling method that is also used for log filters.
|
// `eth_getFilterChanges` polling method that is also used for log filters.
|
||||||
func (api *FilterAPI) NewPendingTransactionFilter() rpc.ID {
|
func (api *FilterAPI) NewPendingTransactionFilter(fullTx *bool) rpc.ID {
|
||||||
var (
|
var (
|
||||||
pendingTxs = make(chan []*types.Transaction)
|
pendingTxs = make(chan []*types.Transaction)
|
||||||
pendingTxSub = api.events.SubscribePendingTxs(pendingTxs)
|
pendingTxSub = api.events.SubscribePendingTxs(pendingTxs)
|
||||||
)
|
)
|
||||||
|
|
||||||
api.filtersMu.Lock()
|
api.filtersMu.Lock()
|
||||||
api.filters[pendingTxSub.ID] = &filter{typ: PendingTransactionsSubscription, deadline: time.NewTimer(api.timeout), txs: make([]*types.Transaction, 0), s: pendingTxSub}
|
api.filters[pendingTxSub.ID] = &filter{typ: PendingTransactionsSubscription, fullTx: fullTx != nil && *fullTx, deadline: time.NewTimer(api.timeout), txs: make([]*types.Transaction, 0), s: pendingTxSub}
|
||||||
api.filtersMu.Unlock()
|
api.filtersMu.Unlock()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -412,6 +413,9 @@ func (api *FilterAPI) GetFilterChanges(id rpc.ID) (interface{}, error) {
|
|||||||
api.filtersMu.Lock()
|
api.filtersMu.Lock()
|
||||||
defer api.filtersMu.Unlock()
|
defer api.filtersMu.Unlock()
|
||||||
|
|
||||||
|
chainConfig := api.sys.backend.ChainConfig()
|
||||||
|
latest := api.sys.backend.CurrentHeader()
|
||||||
|
|
||||||
if f, found := api.filters[id]; found {
|
if f, found := api.filters[id]; found {
|
||||||
if !f.deadline.Stop() {
|
if !f.deadline.Stop() {
|
||||||
// timer expired but filter is not yet removed in timeout loop
|
// timer expired but filter is not yet removed in timeout loop
|
||||||
@ -426,9 +430,21 @@ func (api *FilterAPI) GetFilterChanges(id rpc.ID) (interface{}, error) {
|
|||||||
f.hashes = nil
|
f.hashes = nil
|
||||||
return returnHashes(hashes), nil
|
return returnHashes(hashes), nil
|
||||||
case PendingTransactionsSubscription:
|
case PendingTransactionsSubscription:
|
||||||
txs := f.txs
|
if f.fullTx {
|
||||||
f.txs = nil
|
txs := make([]*ethapi.RPCTransaction, 0, len(f.txs))
|
||||||
return txs, nil
|
for _, tx := range f.txs {
|
||||||
|
txs = append(txs, ethapi.NewRPCPendingTransaction(tx, latest, chainConfig))
|
||||||
|
}
|
||||||
|
f.txs = nil
|
||||||
|
return txs, nil
|
||||||
|
} else {
|
||||||
|
hashes := make([]common.Hash, 0, len(f.txs))
|
||||||
|
for _, tx := range f.txs {
|
||||||
|
hashes = append(hashes, tx.Hash())
|
||||||
|
}
|
||||||
|
f.txs = nil
|
||||||
|
return hashes, nil
|
||||||
|
}
|
||||||
case LogsSubscription, MinedAndPendingLogsSubscription:
|
case LogsSubscription, MinedAndPendingLogsSubscription:
|
||||||
logs := f.logs
|
logs := f.logs
|
||||||
f.logs = nil
|
f.logs = nil
|
||||||
|
@ -37,6 +37,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
@ -52,11 +53,12 @@ type testBackend struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *testBackend) ChainConfig() *params.ChainConfig {
|
func (b *testBackend) ChainConfig() *params.ChainConfig {
|
||||||
panic("implement me")
|
return params.TestChainConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *testBackend) CurrentHeader() *types.Header {
|
func (b *testBackend) CurrentHeader() *types.Header {
|
||||||
panic("implement me")
|
hdr, _ := b.HeaderByNumber(context.TODO(), rpc.LatestBlockNumber)
|
||||||
|
return hdr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *testBackend) ChainDb() ethdb.Database {
|
func (b *testBackend) ChainDb() ethdb.Database {
|
||||||
@ -256,10 +258,10 @@ func TestPendingTxFilter(t *testing.T) {
|
|||||||
types.NewTransaction(4, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil),
|
types.NewTransaction(4, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil),
|
||||||
}
|
}
|
||||||
|
|
||||||
txs []*types.Transaction
|
hashes []common.Hash
|
||||||
)
|
)
|
||||||
|
|
||||||
fid0 := api.NewPendingTransactionFilter()
|
fid0 := api.NewPendingTransactionFilter(nil)
|
||||||
|
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
backend.txFeed.Send(core.NewTxsEvent{Txs: transactions})
|
backend.txFeed.Send(core.NewTxsEvent{Txs: transactions})
|
||||||
@ -271,7 +273,64 @@ func TestPendingTxFilter(t *testing.T) {
|
|||||||
t.Fatalf("Unable to retrieve logs: %v", err)
|
t.Fatalf("Unable to retrieve logs: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tx := results.([]*types.Transaction)
|
h := results.([]common.Hash)
|
||||||
|
hashes = append(hashes, h...)
|
||||||
|
if len(hashes) >= len(transactions) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// check timeout
|
||||||
|
if time.Now().After(timeout) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(hashes) != len(transactions) {
|
||||||
|
t.Errorf("invalid number of transactions, want %d transactions(s), got %d", len(transactions), len(hashes))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i := range hashes {
|
||||||
|
if hashes[i] != transactions[i].Hash() {
|
||||||
|
t.Errorf("hashes[%d] invalid, want %x, got %x", i, transactions[i].Hash(), hashes[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestPendingTxFilterFullTx tests whether pending tx filters retrieve all pending transactions that are posted to the event mux.
|
||||||
|
func TestPendingTxFilterFullTx(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
var (
|
||||||
|
db = rawdb.NewMemoryDatabase()
|
||||||
|
backend, sys = newTestFilterSystem(t, db, Config{})
|
||||||
|
api = NewFilterAPI(sys, false)
|
||||||
|
|
||||||
|
transactions = []*types.Transaction{
|
||||||
|
types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil),
|
||||||
|
types.NewTransaction(1, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil),
|
||||||
|
types.NewTransaction(2, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil),
|
||||||
|
types.NewTransaction(3, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil),
|
||||||
|
types.NewTransaction(4, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil),
|
||||||
|
}
|
||||||
|
|
||||||
|
txs []*ethapi.RPCTransaction
|
||||||
|
)
|
||||||
|
|
||||||
|
fullTx := true
|
||||||
|
fid0 := api.NewPendingTransactionFilter(&fullTx)
|
||||||
|
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
backend.txFeed.Send(core.NewTxsEvent{Txs: transactions})
|
||||||
|
|
||||||
|
timeout := time.Now().Add(1 * time.Second)
|
||||||
|
for {
|
||||||
|
results, err := api.GetFilterChanges(fid0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unable to retrieve logs: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tx := results.([]*ethapi.RPCTransaction)
|
||||||
txs = append(txs, tx...)
|
txs = append(txs, tx...)
|
||||||
if len(txs) >= len(transactions) {
|
if len(txs) >= len(transactions) {
|
||||||
break
|
break
|
||||||
@ -289,8 +348,8 @@ func TestPendingTxFilter(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
for i := range txs {
|
for i := range txs {
|
||||||
if txs[i].Hash() != transactions[i].Hash() {
|
if txs[i].Hash != transactions[i].Hash() {
|
||||||
t.Errorf("hashes[%d] invalid, want %x, got %x", i, transactions[i].Hash(), txs[i].Hash())
|
t.Errorf("hashes[%d] invalid, want %x, got %x", i, transactions[i].Hash(), txs[i].Hash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -854,15 +913,15 @@ func TestPendingTxFilterDeadlock(t *testing.T) {
|
|||||||
// timeout either in 100ms or 200ms
|
// timeout either in 100ms or 200ms
|
||||||
fids := make([]rpc.ID, 20)
|
fids := make([]rpc.ID, 20)
|
||||||
for i := 0; i < len(fids); i++ {
|
for i := 0; i < len(fids); i++ {
|
||||||
fid := api.NewPendingTransactionFilter()
|
fid := api.NewPendingTransactionFilter(nil)
|
||||||
fids[i] = fid
|
fids[i] = fid
|
||||||
// Wait for at least one tx to arrive in filter
|
// Wait for at least one tx to arrive in filter
|
||||||
for {
|
for {
|
||||||
txs, err := api.GetFilterChanges(fid)
|
hashes, err := api.GetFilterChanges(fid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Filter should exist: %v\n", err)
|
t.Fatalf("Filter should exist: %v\n", err)
|
||||||
}
|
}
|
||||||
if len(txs.([]*types.Transaction)) > 0 {
|
if len(hashes.([]common.Hash)) > 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
runtime.Gosched()
|
runtime.Gosched()
|
||||||
|
Loading…
Reference in New Issue
Block a user