mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
core: rewrite TestLogsRebirth without event goroutine
This commit is contained in:
parent
440c0123c8
commit
b7ada82611
1 changed files with 100 additions and 182 deletions
|
|
@ -22,7 +22,6 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -981,202 +980,106 @@ func TestLogReorgs(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This EVM code generates a log when the contract is created.
|
||||||
|
var logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
|
||||||
|
|
||||||
|
// This test checks that log events and RemovedLogsEvent are sent
|
||||||
|
// when the chain reorganizes.
|
||||||
func TestLogRebirth(t *testing.T) {
|
func TestLogRebirth(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
|
|
||||||
// this code generates a log
|
|
||||||
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
|
|
||||||
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
|
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
signer = types.NewEIP155Signer(gspec.Config.ChainID)
|
signer = types.NewEIP155Signer(gspec.Config.ChainID)
|
||||||
newLogCh = make(chan bool)
|
engine = ethash.NewFaker()
|
||||||
removeLogCh = make(chan bool)
|
blockchain, _ = NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil)
|
||||||
errMsgCh = make(chan string, 5) // Receive error message from validateLogEvent
|
|
||||||
)
|
)
|
||||||
|
|
||||||
defer func() {
|
|
||||||
n := 5 // 5 is the number of times validateLogEvent is used to create new goroutines
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
if msg := <-errMsgCh; msg != "" {
|
|
||||||
t.Fatal(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// validateLogEvent checks whether the received logs number is equal with expected.
|
|
||||||
validateLogEvent := func(sink interface{}, result chan bool, expect int) {
|
|
||||||
chanval := reflect.ValueOf(sink)
|
|
||||||
chantyp := chanval.Type()
|
|
||||||
if chantyp.Kind() != reflect.Chan || chantyp.ChanDir()&reflect.RecvDir == 0 {
|
|
||||||
errMsgCh <- fmt.Sprintf("invalid channel, given type %v", chantyp)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
errMsgCh <- ""
|
|
||||||
}
|
|
||||||
cnt := 0
|
|
||||||
var recv []reflect.Value
|
|
||||||
timeout := time.After(1 * time.Second)
|
|
||||||
cases := []reflect.SelectCase{{Chan: chanval, Dir: reflect.SelectRecv}, {Chan: reflect.ValueOf(timeout), Dir: reflect.SelectRecv}}
|
|
||||||
for {
|
|
||||||
chose, v, _ := reflect.Select(cases)
|
|
||||||
if chose == 1 {
|
|
||||||
// Not enough event received
|
|
||||||
result <- false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cnt += 1
|
|
||||||
recv = append(recv, v)
|
|
||||||
if cnt == expect {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
done := time.After(50 * time.Millisecond)
|
|
||||||
cases = cases[:1]
|
|
||||||
cases = append(cases, reflect.SelectCase{Chan: reflect.ValueOf(done), Dir: reflect.SelectRecv})
|
|
||||||
chose, _, _ := reflect.Select(cases)
|
|
||||||
// If chose equal 0, it means receiving redundant events.
|
|
||||||
if chose == 1 {
|
|
||||||
result <- true
|
|
||||||
} else {
|
|
||||||
result <- false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
logsCh := make(chan []*types.Log)
|
// The event channels.
|
||||||
blockchain.SubscribeLogsEvent(logsCh)
|
newLogCh := make(chan []*types.Log, 10)
|
||||||
|
rmLogsCh := make(chan RemovedLogsEvent, 10)
|
||||||
rmLogsCh := make(chan RemovedLogsEvent)
|
blockchain.SubscribeLogsEvent(newLogCh)
|
||||||
blockchain.SubscribeRemovedLogsEvent(rmLogsCh)
|
blockchain.SubscribeRemovedLogsEvent(rmLogsCh)
|
||||||
|
|
||||||
chain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) {
|
// This chain contains a single log.
|
||||||
|
chain, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2, func(i int, gen *BlockGen) {
|
||||||
if i == 1 {
|
if i == 1 {
|
||||||
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), code), signer, key1)
|
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), logCode), signer, key1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tx: %v", err)
|
t.Fatalf("failed to create tx: %v", err)
|
||||||
}
|
}
|
||||||
gen.AddTx(tx)
|
gen.AddTx(tx)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Spawn a goroutine to receive log events
|
|
||||||
go validateLogEvent(logsCh, newLogCh, 1)
|
|
||||||
if _, err := blockchain.InsertChain(chain); err != nil {
|
if _, err := blockchain.InsertChain(chain); err != nil {
|
||||||
t.Fatalf("failed to insert chain: %v", err)
|
t.Fatalf("failed to insert chain: %v", err)
|
||||||
}
|
}
|
||||||
if !<-newLogCh {
|
checkLogEvents(t, newLogCh, rmLogsCh, 1, 0)
|
||||||
t.Fatal("failed to receive new log event")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate long reorg chain
|
// Generate long reorg chain containing another log. Inserting the
|
||||||
forkChain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) {
|
// chain removes one log and adds one.
|
||||||
|
forkChain, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2, func(i int, gen *BlockGen) {
|
||||||
if i == 1 {
|
if i == 1 {
|
||||||
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), code), signer, key1)
|
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), logCode), signer, key1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tx: %v", err)
|
t.Fatalf("failed to create tx: %v", err)
|
||||||
}
|
}
|
||||||
gen.AddTx(tx)
|
gen.AddTx(tx)
|
||||||
// Higher block difficulty
|
gen.OffsetTime(-9) // higher block difficulty
|
||||||
gen.OffsetTime(-9)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Spawn a goroutine to receive log events
|
|
||||||
go validateLogEvent(logsCh, newLogCh, 1)
|
|
||||||
go validateLogEvent(rmLogsCh, removeLogCh, 1)
|
|
||||||
if _, err := blockchain.InsertChain(forkChain); err != nil {
|
if _, err := blockchain.InsertChain(forkChain); err != nil {
|
||||||
t.Fatalf("failed to insert forked chain: %v", err)
|
t.Fatalf("failed to insert forked chain: %v", err)
|
||||||
}
|
}
|
||||||
if !<-newLogCh {
|
checkLogEvents(t, newLogCh, rmLogsCh, 1, 1)
|
||||||
t.Fatal("failed to receive new log event")
|
|
||||||
}
|
|
||||||
if !<-removeLogCh {
|
|
||||||
t.Fatal("failed to receive removed log event")
|
|
||||||
}
|
|
||||||
|
|
||||||
newBlocks, _ := GenerateChain(params.TestChainConfig, chain[len(chain)-1], ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {})
|
// This chain segment is rooted in the original chain, but doesn't contain any logs.
|
||||||
go validateLogEvent(logsCh, newLogCh, 1)
|
// When inserting it, the canonical chain switches away from forkChain and re-emits
|
||||||
go validateLogEvent(rmLogsCh, removeLogCh, 1)
|
// the log event for the old chain, as well as a RemovedLogsEvent for forkChain.
|
||||||
|
newBlocks, _ := GenerateChain(params.TestChainConfig, chain[len(chain)-1], engine, db, 1, func(i int, gen *BlockGen) {})
|
||||||
if _, err := blockchain.InsertChain(newBlocks); err != nil {
|
if _, err := blockchain.InsertChain(newBlocks); err != nil {
|
||||||
t.Fatalf("failed to insert forked chain: %v", err)
|
t.Fatalf("failed to insert forked chain: %v", err)
|
||||||
}
|
}
|
||||||
// Rebirth logs should omit a newLogEvent
|
checkLogEvents(t, newLogCh, rmLogsCh, 1, 1)
|
||||||
if !<-newLogCh {
|
|
||||||
t.Fatal("failed to receive new log event")
|
|
||||||
}
|
|
||||||
// Ensure removedLog events received
|
|
||||||
if !<-removeLogCh {
|
|
||||||
t.Fatal("failed to receive removed log event")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This test is a variation of TestLogRebirth. It verifies that log events are emitted
|
||||||
|
// when a side chain containing log events overtakes the canonical chain.
|
||||||
func TestSideLogRebirth(t *testing.T) {
|
func TestSideLogRebirth(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
|
|
||||||
// this code generates a log
|
|
||||||
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
|
|
||||||
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
|
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
signer = types.NewEIP155Signer(gspec.Config.ChainID)
|
signer = types.NewEIP155Signer(gspec.Config.ChainID)
|
||||||
newLogCh = make(chan bool)
|
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// listenNewLog checks whether the received logs number is equal with expected.
|
|
||||||
listenNewLog := func(sink chan []*types.Log, expect int) {
|
|
||||||
cnt := 0
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case logs := <-sink:
|
|
||||||
cnt += len(logs)
|
|
||||||
case <-time.NewTimer(5 * time.Second).C:
|
|
||||||
// new logs timeout
|
|
||||||
newLogCh <- false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if cnt == expect {
|
|
||||||
break
|
|
||||||
} else if cnt > expect {
|
|
||||||
// redundant logs received
|
|
||||||
newLogCh <- false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
case <-sink:
|
|
||||||
// redundant logs received
|
|
||||||
newLogCh <- false
|
|
||||||
case <-time.NewTimer(100 * time.Millisecond).C:
|
|
||||||
newLogCh <- true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
logsCh := make(chan []*types.Log)
|
newLogCh := make(chan []*types.Log, 10)
|
||||||
blockchain.SubscribeLogsEvent(logsCh)
|
rmLogsCh := make(chan RemovedLogsEvent, 10)
|
||||||
|
blockchain.SubscribeLogsEvent(newLogCh)
|
||||||
|
blockchain.SubscribeRemovedLogsEvent(rmLogsCh)
|
||||||
|
|
||||||
chain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) {
|
chain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) {
|
||||||
if i == 1 {
|
if i == 1 {
|
||||||
// Higher block difficulty
|
gen.OffsetTime(-9) // higher block difficulty
|
||||||
gen.OffsetTime(-9)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if _, err := blockchain.InsertChain(chain); err != nil {
|
if _, err := blockchain.InsertChain(chain); err != nil {
|
||||||
t.Fatalf("failed to insert forked chain: %v", err)
|
t.Fatalf("failed to insert forked chain: %v", err)
|
||||||
}
|
}
|
||||||
|
checkLogEvents(t, newLogCh, rmLogsCh, 0, 0)
|
||||||
|
|
||||||
// Generate side chain with lower difficulty
|
// Generate side chain with lower difficulty
|
||||||
sideChain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) {
|
sideChain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) {
|
||||||
if i == 1 {
|
if i == 1 {
|
||||||
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), code), signer, key1)
|
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), logCode), signer, key1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tx: %v", err)
|
t.Fatalf("failed to create tx: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1186,16 +1089,31 @@ func TestSideLogRebirth(t *testing.T) {
|
||||||
if _, err := blockchain.InsertChain(sideChain); err != nil {
|
if _, err := blockchain.InsertChain(sideChain); err != nil {
|
||||||
t.Fatalf("failed to insert forked chain: %v", err)
|
t.Fatalf("failed to insert forked chain: %v", err)
|
||||||
}
|
}
|
||||||
|
checkLogEvents(t, newLogCh, rmLogsCh, 0, 0)
|
||||||
|
|
||||||
// Generate a new block based on side chain
|
// Generate a new block based on side chain.
|
||||||
newBlocks, _ := GenerateChain(params.TestChainConfig, sideChain[len(sideChain)-1], ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {})
|
newBlocks, _ := GenerateChain(params.TestChainConfig, sideChain[len(sideChain)-1], ethash.NewFaker(), db, 1, func(i int, gen *BlockGen) {})
|
||||||
go listenNewLog(logsCh, 1)
|
|
||||||
if _, err := blockchain.InsertChain(newBlocks); err != nil {
|
if _, err := blockchain.InsertChain(newBlocks); err != nil {
|
||||||
t.Fatalf("failed to insert forked chain: %v", err)
|
t.Fatalf("failed to insert forked chain: %v", err)
|
||||||
}
|
}
|
||||||
// Rebirth logs should omit a newLogEvent
|
checkLogEvents(t, newLogCh, rmLogsCh, 1, 0)
|
||||||
if !<-newLogCh {
|
}
|
||||||
t.Fatalf("failed to receive new log event")
|
|
||||||
|
func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan RemovedLogsEvent, wantNew, wantRemoved int) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
if len(logsCh) != wantNew {
|
||||||
|
t.Fatalf("wrong number of log events: got %d, want %d", len(logsCh), wantNew)
|
||||||
|
}
|
||||||
|
if len(rmLogsCh) != wantRemoved {
|
||||||
|
t.Fatalf("wrong number of removed log events: got %d, want %d", len(rmLogsCh), wantRemoved)
|
||||||
|
}
|
||||||
|
// Drain events.
|
||||||
|
for i := 0; i < len(logsCh); i++ {
|
||||||
|
<-logsCh
|
||||||
|
}
|
||||||
|
for i := 0; i < len(rmLogsCh); i++ {
|
||||||
|
<-rmLogsCh
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue