github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/gossip/common_test.go (about) 1 package gossip 2 3 import ( 4 "context" 5 "crypto/ecdsa" 6 "errors" 7 "fmt" 8 "math" 9 "math/big" 10 "sync" 11 "time" 12 13 "github.com/unicornultrafoundation/go-helios/consensus" 14 "github.com/unicornultrafoundation/go-helios/hash" 15 "github.com/unicornultrafoundation/go-helios/native/dag" 16 "github.com/unicornultrafoundation/go-helios/native/idx" 17 "github.com/unicornultrafoundation/go-helios/utils/cachescale" 18 go_u2u "github.com/unicornultrafoundation/go-u2u" 19 "github.com/unicornultrafoundation/go-u2u/accounts/abi/bind" 20 "github.com/unicornultrafoundation/go-u2u/common" 21 "github.com/unicornultrafoundation/go-u2u/common/hexutil" 22 "github.com/unicornultrafoundation/go-u2u/core/state" 23 "github.com/unicornultrafoundation/go-u2u/core/types" 24 "github.com/unicornultrafoundation/go-u2u/core/vm" 25 "github.com/unicornultrafoundation/go-u2u/crypto" 26 "github.com/unicornultrafoundation/go-u2u/log" 27 28 "github.com/unicornultrafoundation/go-u2u/evmcore" 29 "github.com/unicornultrafoundation/go-u2u/gossip/blockproc" 30 "github.com/unicornultrafoundation/go-u2u/gossip/emitter" 31 "github.com/unicornultrafoundation/go-u2u/integration/makefakegenesis" 32 "github.com/unicornultrafoundation/go-u2u/native" 33 "github.com/unicornultrafoundation/go-u2u/native/iblockproc" 34 "github.com/unicornultrafoundation/go-u2u/native/validatorpk" 35 "github.com/unicornultrafoundation/go-u2u/u2u" 36 "github.com/unicornultrafoundation/go-u2u/utils" 37 "github.com/unicornultrafoundation/go-u2u/utils/adapters/vecmt2dagidx" 38 "github.com/unicornultrafoundation/go-u2u/valkeystore" 39 "github.com/unicornultrafoundation/go-u2u/vecmt" 40 ) 41 42 const ( 43 gasLimit = uint64(21000) 44 maxGasLimit = uint64(6000000) 45 genesisBalance = 1e18 46 genesisStake = 2 * 4e6 47 48 maxEpochDuration = time.Hour 49 sameEpoch = maxEpochDuration / 1000 50 nextEpoch = maxEpochDuration 51 ) 52 53 type callbacks struct { 54 buildEvent func(e *native.MutableEventPayload) 55 onEventConfirmed func(e native.EventI) 56 } 57 58 type testEnv struct { 59 t time.Time 60 nonces map[common.Address]uint64 61 callback callbacks 62 *Service 63 signer valkeystore.SignerI 64 pubkeys []validatorpk.PubKey 65 } 66 67 func panics(name string) func(error) { 68 return func(err error) { 69 log.Crit(fmt.Sprintf("%s error", name), "err", err) 70 } 71 } 72 73 type testGossipStoreAdapter struct { 74 *Store 75 } 76 77 func (g *testGossipStoreAdapter) GetEvent(id hash.Event) dag.Event { 78 e := g.Store.GetEvent(id) 79 if e == nil { 80 return nil 81 } 82 return e 83 } 84 85 func makeTestEngine(gdb *Store) (*consensus.Consensus, *vecmt.Index) { 86 cdb := consensus.NewMemStore() 87 _ = cdb.ApplyGenesis(&consensus.Genesis{ 88 Epoch: gdb.GetEpoch(), 89 Validators: gdb.GetValidators(), 90 }) 91 vecClock := vecmt.NewIndex(panics("Vector clock"), vecmt.LiteConfig()) 92 engine := consensus.NewConsensus(cdb, &testGossipStoreAdapter{gdb}, vecmt2dagidx.Wrap(vecClock), panics("Hashgraph"), consensus.LiteConfig()) 93 return engine, vecClock 94 } 95 96 type testEmitterWorldExternal struct { 97 emitter.External 98 env *testEnv 99 } 100 101 func (em testEmitterWorldExternal) Build(e *native.MutableEventPayload, onIndexed func()) error { 102 e.SetCreationTime(native.Timestamp(em.env.t.UnixNano())) 103 if em.env.callback.buildEvent != nil { 104 em.env.callback.buildEvent(e) 105 } 106 return em.External.Build(e, onIndexed) 107 } 108 109 func (em testEmitterWorldExternal) Broadcast(*native.EventPayload) {} 110 111 type testConfirmedEventsProcessor struct { 112 blockproc.ConfirmedEventsProcessor 113 env *testEnv 114 } 115 116 func (p testConfirmedEventsProcessor) ProcessConfirmedEvent(e native.EventI) { 117 if p.env.callback.onEventConfirmed != nil { 118 p.env.callback.onEventConfirmed(e) 119 } 120 p.ConfirmedEventsProcessor.ProcessConfirmedEvent(e) 121 } 122 123 type testConfirmedEventsModule struct { 124 blockproc.ConfirmedEventsModule 125 env *testEnv 126 } 127 128 func (m testConfirmedEventsModule) Start(bs iblockproc.BlockState, es iblockproc.EpochState) blockproc.ConfirmedEventsProcessor { 129 p := m.ConfirmedEventsModule.Start(bs, es) 130 return testConfirmedEventsProcessor{p, m.env} 131 } 132 133 func newTestEnv(firstEpoch idx.Epoch, validatorsNum idx.Validator) *testEnv { 134 rules := u2u.FakeNetRules() 135 rules.Epochs.MaxEpochDuration = native.Timestamp(maxEpochDuration) 136 rules.Blocks.MaxEmptyBlockSkipPeriod = 0 137 138 genStore := makefakegenesis.FakeGenesisStoreWithRulesAndStart(validatorsNum, utils.ToU2U(genesisBalance), utils.ToU2U(genesisStake), rules, firstEpoch, 2) 139 genesis := genStore.Genesis() 140 141 store := NewMemStore() 142 _, err := store.ApplyGenesis(genesis) 143 if err != nil { 144 panic(err) 145 } 146 147 // install blockProc callbacks 148 env := &testEnv{ 149 t: store.GetGenesisTime().Time(), 150 nonces: make(map[common.Address]uint64), 151 } 152 blockProc := DefaultBlockProc() 153 blockProc.EventsModule = testConfirmedEventsModule{blockProc.EventsModule, env} 154 155 engine, vecClock := makeTestEngine(store) 156 157 // create the service 158 txPool := &dummyTxPool{} 159 env.Service, err = newService(DefaultConfig(cachescale.Identity), store, blockProc, engine, vecClock, func(_ evmcore.StateReader) TxPool { 160 return txPool 161 }) 162 if err != nil { 163 panic(err) 164 } 165 txPool.signer = env.EthAPI.signer 166 err = engine.Bootstrap(env.GetConsensusCallbacks()) 167 if err != nil { 168 panic(err) 169 } 170 171 valKeystore := valkeystore.NewDefaultMemKeystore() 172 env.signer = valkeystore.NewSigner(valKeystore) 173 174 // register emitters 175 for i := idx.Validator(0); i < validatorsNum; i++ { 176 cfg := emitter.DefaultConfig() 177 vid := store.GetValidators().GetID(i) 178 pubkey := store.GetEpochState().ValidatorProfiles[vid].PubKey 179 cfg.Validator = emitter.ValidatorConfig{ 180 ID: vid, 181 PubKey: pubkey, 182 } 183 cfg.EmitIntervals = emitter.EmitIntervals{} 184 cfg.MaxParents = idx.Event(validatorsNum/2 + 1) 185 cfg.MaxTxsPerAddress = 10000000 186 _ = valKeystore.Add(pubkey, crypto.FromECDSA(makefakegenesis.FakeKey(vid)), validatorpk.FakePassword) 187 _ = valKeystore.Unlock(pubkey, validatorpk.FakePassword) 188 world := env.EmitterWorld(env.signer) 189 world.External = testEmitterWorldExternal{world.External, env} 190 em := emitter.NewEmitter(cfg, world) 191 env.RegisterEmitter(em) 192 env.pubkeys = append(env.pubkeys, pubkey) 193 em.Start() 194 } 195 196 _ = env.store.GenerateSnapshotAt(common.Hash(store.GetBlockState().FinalizedStateRoot), false) 197 env.blockProcTasks.Start(1) 198 env.verWatcher.Start() 199 200 return env 201 } 202 203 func (env *testEnv) Close() { 204 env.verWatcher.Stop() 205 env.store.Close() 206 env.tflusher.Stop() 207 } 208 209 func (env *testEnv) GetEvmStateReader() *EvmStateReader { 210 return &EvmStateReader{ 211 store: env.store, 212 } 213 } 214 215 func (env *testEnv) ApplyTxs(spent time.Duration, txs ...*types.Transaction) (types.Receipts, error) { 216 env.t = env.t.Add(spent) 217 218 externalReceipts := make(types.Receipts, 0, len(txs)) 219 220 env.txpool.AddRemotes(txs) 221 defer env.txpool.(*dummyTxPool).Clear() 222 newBlocks := make(chan evmcore.ChainHeadNotify) 223 chainHeadSub := env.feed.SubscribeNewBlock(newBlocks) 224 mu := &sync.Mutex{} 225 go func() { 226 for b := range newBlocks { 227 if len(b.Block.Transactions) == 0 { 228 continue 229 } 230 receipts := env.store.evm.GetReceipts(idx.Block(b.Block.Number.Uint64()), env.EthAPI.signer, b.Block.Hash, b.Block.Transactions) 231 for i, tx := range b.Block.Transactions { 232 if r, _, _ := tx.RawSignatureValues(); r.Sign() != 0 { 233 mu.Lock() 234 externalReceipts = append(externalReceipts, receipts[i]) 235 mu.Unlock() 236 env.txpool.(*dummyTxPool).Delete(tx.Hash()) 237 } 238 } 239 if externalReceipts.Len() == len(txs) { 240 chainHeadSub.Unsubscribe() 241 close(newBlocks) 242 break 243 } 244 } 245 }() 246 err := env.EmitUntil(func() bool { 247 mu.Lock() 248 defer mu.Unlock() 249 return externalReceipts.Len() == len(txs) 250 }) 251 252 return externalReceipts, err 253 } 254 255 func (env *testEnv) ApplyMPs(spent time.Duration, mps ...native.MisbehaviourProof) error { 256 env.t = env.t.Add(spent) 257 258 // all callbacks are non-async 259 lastEpoch := idx.Epoch(0) 260 env.callback.buildEvent = func(e *native.MutableEventPayload) { 261 if e.Epoch() > lastEpoch { 262 e.SetMisbehaviourProofs(mps) 263 lastEpoch = e.Epoch() 264 } 265 } 266 confirmed := false 267 env.callback.onEventConfirmed = func(_e native.EventI) { 268 // ensure that not only MPs were confirmed, but also no new MPs will be confirmed in future 269 if _e.AnyMisbehaviourProofs() && _e.Epoch() == lastEpoch { 270 confirmed = true 271 // sanity check for gas used 272 e := env.store.GetEventPayload(_e.ID()) 273 rule := env.store.GetRules().Economy.Gas 274 if e.GasPowerUsed() < rule.EventGas+uint64(len(e.MisbehaviourProofs()))*rule.MisbehaviourProofGas { 275 panic("GasPowerUsed calculation doesn't include MisbehaviourProofGas") 276 } 277 } 278 } 279 defer func() { 280 env.callback.buildEvent = nil 281 }() 282 283 return env.EmitUntil(func() bool { 284 return confirmed 285 }) 286 } 287 288 func (env *testEnv) EmitUntil(stop func() bool) error { 289 t := time.Now() 290 291 for !stop() { 292 for _, em := range env.emitters { 293 _, err := em.EmitEvent() 294 if err != nil { 295 return err 296 } 297 } 298 env.WaitBlockEnd() 299 env.t = env.t.Add(time.Second) 300 if time.Since(t) > 30*time.Second { 301 panic("block doesn't get processed") 302 } 303 } 304 return nil 305 } 306 307 func (env *testEnv) Transfer(from, to idx.ValidatorID, amount *big.Int) *types.Transaction { 308 sender := env.Address(from) 309 nonce, _ := env.PendingNonceAt(nil, sender) 310 env.incNonce(sender) 311 key := env.privateKey(from) 312 receiver := env.Address(to) 313 gp := new(big.Int).SetUint64(1e12) 314 tx := types.NewTransaction(nonce, receiver, amount, gasLimit, gp, nil) 315 tx, err := types.SignTx(tx, env.EthAPI.signer, key) 316 if err != nil { 317 panic(err) 318 } 319 320 return tx 321 } 322 323 func (env *testEnv) Contract(from idx.ValidatorID, amount *big.Int, hex string) *types.Transaction { 324 sender := env.Address(from) 325 nonce, _ := env.PendingNonceAt(nil, sender) 326 env.incNonce(sender) 327 key := env.privateKey(from) 328 gp := env.store.GetRules().Economy.MinGasPrice 329 data := hexutil.MustDecode(hex) 330 tx := types.NewContractCreation(nonce, amount, maxGasLimit, gp, data) 331 tx, err := types.SignTx(tx, env.EthAPI.signer, key) 332 if err != nil { 333 panic(err) 334 } 335 336 return tx 337 } 338 339 func (env *testEnv) privateKey(n idx.ValidatorID) *ecdsa.PrivateKey { 340 key := makefakegenesis.FakeKey(n) 341 return key 342 } 343 344 func (env *testEnv) Address(n idx.ValidatorID) common.Address { 345 key := makefakegenesis.FakeKey(n) 346 addr := crypto.PubkeyToAddress(key.PublicKey) 347 return addr 348 } 349 350 func (env *testEnv) Payer(n idx.ValidatorID, amounts ...*big.Int) *bind.TransactOpts { 351 key := env.privateKey(n) 352 t, _ := bind.NewKeyedTransactorWithChainID(key, new(big.Int).SetUint64(env.store.GetRules().NetworkID)) 353 nonce, _ := env.PendingNonceAt(nil, env.Address(n)) 354 t.Nonce = big.NewInt(int64(nonce)) 355 t.Value = big.NewInt(0) 356 for _, amount := range amounts { 357 t.Value.Add(t.Value, amount) 358 } 359 t.GasLimit = env.GetEvmStateReader().MaxGasLimit() 360 t.GasPrice = env.GetEvmStateReader().MinGasPrice() 361 362 return t 363 } 364 365 func (env *testEnv) Pay(n idx.ValidatorID, amounts ...*big.Int) *bind.TransactOpts { 366 t := env.Payer(n, amounts...) 367 env.incNonce(t.From) 368 369 return t 370 } 371 372 func (env *testEnv) ReadOnly() *bind.CallOpts { 373 return &bind.CallOpts{} 374 } 375 376 func (env *testEnv) State() *state.StateDB { 377 statedb, _ := env.store.evm.StateDB(env.store.GetBlockState().FinalizedStateRoot) 378 return statedb 379 } 380 381 func (env *testEnv) incNonce(account common.Address) { 382 env.nonces[account] += 1 383 } 384 385 /* 386 * bind.ContractCaller interface 387 */ 388 389 var ( 390 errBlockNumberUnsupported = errors.New("simulatedBackend cannot access blocks other than the latest block") 391 ) 392 393 // CodeAt returns the code of the given account. This is needed to differentiate 394 // between contract internal errors and the local chain being out of sync. 395 func (env *testEnv) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) { 396 if blockNumber != nil && idx.Block(blockNumber.Uint64()) != env.store.GetLatestBlockIndex() { 397 return nil, errBlockNumberUnsupported 398 } 399 400 code := env.State().GetCode(contract) 401 return code, nil 402 } 403 404 // ContractCall executes an Ethereum contract call with the specified data as the 405 // input. 406 func (env *testEnv) CallContract(ctx context.Context, call go_u2u.CallMsg, blockNumber *big.Int) ([]byte, error) { 407 if blockNumber != nil && idx.Block(blockNumber.Uint64()) != env.store.GetLatestBlockIndex() { 408 return nil, errBlockNumberUnsupported 409 } 410 411 h := env.GetEvmStateReader().GetHeader(common.Hash{}, uint64(env.store.GetLatestBlockIndex())) 412 block := &evmcore.EvmBlock{ 413 EvmHeader: *h, 414 } 415 416 rval, _, _, err := env.callContract(ctx, call, block, env.State()) 417 return rval, err 418 } 419 420 func (env *testEnv) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { 421 var num64 uint64 422 if number == nil { 423 num64 = uint64(env.store.GetLatestBlockIndex()) 424 } else { 425 num64 = number.Uint64() 426 } 427 return env.GetEvmStateReader().GetHeader(common.Hash{}, num64).EthHeader(), nil 428 } 429 430 // callContract implements common code between normal and pending contract calls. 431 // state is modified during execution, make sure to copy it if necessary. 432 func (env *testEnv) callContract( 433 ctx context.Context, call go_u2u.CallMsg, block *evmcore.EvmBlock, state *state.StateDB, 434 ) ( 435 ret []byte, usedGas uint64, failed bool, err error, 436 ) { 437 // Ensure message is initialized properly. 438 if call.GasPrice == nil { 439 call.GasPrice = big.NewInt(1) 440 } 441 if call.Gas == 0 { 442 call.Gas = 50000000 443 } 444 if call.Value == nil { 445 call.Value = new(big.Int) 446 } 447 // Set infinite balance to the fake caller account. 448 from := state.GetOrNewStateObject(call.From) 449 from.SetBalance(big.NewInt(math.MaxInt64)) 450 451 msg := callmsg{call} 452 453 // Create a new environment which holds all relevant information 454 // about the transaction and calling mechanisms. 455 txContext := evmcore.NewEVMTxContext(msg) 456 context := evmcore.NewEVMBlockContext(block.Header(), env.GetEvmStateReader(), nil) 457 vmenv := vm.NewEVM(context, txContext, state, env.store.GetEvmChainConfig(), u2u.DefaultVMConfig) 458 gaspool := new(evmcore.GasPool).AddGas(math.MaxUint64) 459 res, err := evmcore.NewStateTransition(vmenv, msg, gaspool).TransitionDb() 460 461 ret, usedGas, failed = res.Return(), res.UsedGas, res.Failed() 462 return 463 } 464 465 /* 466 * bind.ContractTransactor interface 467 */ 468 469 // PendingCodeAt returns the code of the given account in the pending state. 470 func (env *testEnv) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) { 471 code := env.State().GetCode(account) 472 return code, nil 473 } 474 475 // PendingNonceAt retrieves the current pending nonce associated with an account. 476 func (env *testEnv) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { 477 nonce := env.nonces[account] 478 return nonce, nil 479 } 480 481 // SuggestGasTipCap retrieves the currently suggested gas price tip to allow a timely 482 // execution of a transaction. 483 func (env *testEnv) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { 484 return new(big.Int), nil 485 } 486 487 // SuggestGasTipCap retrieves the currently suggested gas price to allow a timely 488 // execution of a transaction. 489 func (env *testEnv) SuggestGasPrice(ctx context.Context) (*big.Int, error) { 490 return env.store.GetRules().Economy.MinGasPrice, nil 491 } 492 493 // EstimateGas tries to estimate the gas needed to execute a specific 494 // transaction based on the current pending state of the backend blockchain. 495 // There is no guarantee that this is the true gas limit requirement as other 496 // transactions may be added or removed by miners, but it should provide a basis 497 // for setting a reasonable default. 498 func (env *testEnv) EstimateGas(ctx context.Context, call go_u2u.CallMsg) (gas uint64, err error) { 499 if call.To == nil { 500 gas = gasLimit * 10000 501 } else { 502 gas = gasLimit * 10 503 } 504 return 505 } 506 507 // SendTransaction injects the transaction into the pending pool for execution. 508 func (env *testEnv) SendTransaction(ctx context.Context, tx *types.Transaction) error { 509 // do nothing to avoid executing by transactor, only generating needed 510 return nil 511 } 512 513 /* 514 * bind.ContractFilterer interface 515 */ 516 517 // FilterLogs executes a log filter operation, blocking during execution and 518 // returning all the results in one batch. 519 func (env *testEnv) FilterLogs(ctx context.Context, query go_u2u.FilterQuery) ([]types.Log, error) { 520 panic("not implemented yet") 521 return nil, nil 522 } 523 524 // SubscribeFilterLogs creates a background log filtering operation, returning 525 // a subscription immediately, which can be used to stream the found events. 526 func (env *testEnv) SubscribeFilterLogs(ctx context.Context, query go_u2u.FilterQuery, ch chan<- types.Log) (go_u2u.Subscription, error) { 527 panic("not implemented yet") 528 return nil, nil 529 } 530 531 // callmsg implements evmcore.Message to allow passing it as a transaction simulator. 532 type callmsg struct { 533 go_u2u.CallMsg 534 } 535 536 func (m callmsg) From() common.Address { return m.CallMsg.From } 537 func (m callmsg) To() *common.Address { return m.CallMsg.To } 538 func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice } 539 func (m callmsg) GasTipCap() *big.Int { return m.CallMsg.GasTipCap } 540 func (m callmsg) GasFeeCap() *big.Int { return m.CallMsg.GasFeeCap } 541 func (m callmsg) Gas() uint64 { return m.CallMsg.Gas } 542 func (m callmsg) Value() *big.Int { return m.CallMsg.Value } 543 func (m callmsg) Nonce() uint64 { return 0 } 544 func (m callmsg) IsFake() bool { return true } 545 func (m callmsg) Data() []byte { return m.CallMsg.Data } 546 func (m callmsg) AccessList() types.AccessList { return nil }