github.com/iotexproject/iotex-core@v1.14.1-rc1/state/factory/workingset.go (about) 1 // Copyright (c) 2022 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package factory 7 8 import ( 9 "context" 10 "sort" 11 12 "github.com/iotexproject/go-pkgs/hash" 13 "github.com/iotexproject/iotex-proto/golang/iotextypes" 14 "github.com/pkg/errors" 15 "github.com/prometheus/client_golang/prometheus" 16 "go.uber.org/zap" 17 18 "github.com/iotexproject/iotex-address/address" 19 20 "github.com/iotexproject/iotex-core/action" 21 "github.com/iotexproject/iotex-core/action/protocol" 22 accountutil "github.com/iotexproject/iotex-core/action/protocol/account/util" 23 "github.com/iotexproject/iotex-core/actpool" 24 "github.com/iotexproject/iotex-core/actpool/actioniterator" 25 "github.com/iotexproject/iotex-core/blockchain/block" 26 "github.com/iotexproject/iotex-core/blockchain/genesis" 27 "github.com/iotexproject/iotex-core/pkg/log" 28 "github.com/iotexproject/iotex-core/state" 29 ) 30 31 var ( 32 _stateDBMtc = prometheus.NewCounterVec( 33 prometheus.CounterOpts{ 34 Name: "iotex_state_db", 35 Help: "IoTeX State DB", 36 }, 37 []string{"type"}, 38 ) 39 40 errInvalidSystemActionLayout = errors.New("system action layout is invalid") 41 ) 42 43 func init() { 44 prometheus.MustRegister(_stateDBMtc) 45 } 46 47 type ( 48 workingSet struct { 49 height uint64 50 store workingSetStore 51 finalized bool 52 dock protocol.Dock 53 receipts []*action.Receipt 54 } 55 ) 56 57 func newWorkingSet(height uint64, store workingSetStore) *workingSet { 58 return &workingSet{ 59 height: height, 60 store: store, 61 dock: protocol.NewDock(), 62 } 63 } 64 65 func (ws *workingSet) digest() (hash.Hash256, error) { 66 if !ws.finalized { 67 return hash.ZeroHash256, errors.New("workingset has not been finalized yet") 68 } 69 return ws.store.Digest(), nil 70 } 71 72 func (ws *workingSet) Receipts() ([]*action.Receipt, error) { 73 if !ws.finalized { 74 return nil, errors.New("workingset has not been finalized yet") 75 } 76 return ws.receipts, nil 77 } 78 79 // Height returns the Height of the block being worked on 80 func (ws *workingSet) Height() (uint64, error) { 81 return ws.height, nil 82 } 83 84 func (ws *workingSet) validate(ctx context.Context) error { 85 if ws.finalized { 86 return errors.Errorf("cannot run action on a finalized working set") 87 } 88 blkCtx := protocol.MustGetBlockCtx(ctx) 89 if blkCtx.BlockHeight != ws.height { 90 return errors.Errorf( 91 "invalid block height %d, %d expected", 92 blkCtx.BlockHeight, 93 ws.height, 94 ) 95 } 96 return nil 97 } 98 99 func (ws *workingSet) runActions( 100 ctx context.Context, 101 elps []*action.SealedEnvelope, 102 ) ([]*action.Receipt, error) { 103 // Handle actions 104 receipts := make([]*action.Receipt, 0) 105 for _, elp := range elps { 106 ctxWithActionContext, err := withActionCtx(ctx, elp) 107 if err != nil { 108 return nil, err 109 } 110 receipt, err := ws.runAction(ctxWithActionContext, elp) 111 if err != nil { 112 return nil, errors.Wrap(err, "error when run action") 113 } 114 receipts = append(receipts, receipt) 115 } 116 if protocol.MustGetFeatureCtx(ctx).CorrectTxLogIndex { 117 updateReceiptIndex(receipts) 118 } 119 return receipts, nil 120 } 121 122 func withActionCtx(ctx context.Context, selp *action.SealedEnvelope) (context.Context, error) { 123 var actionCtx protocol.ActionCtx 124 var err error 125 caller := selp.SenderAddress() 126 if caller == nil { 127 return nil, errors.New("failed to get address") 128 } 129 actionCtx.Caller = caller 130 actionCtx.ActionHash, err = selp.Hash() 131 if err != nil { 132 return nil, err 133 } 134 actionCtx.GasPrice = selp.GasPrice() 135 intrinsicGas, err := selp.IntrinsicGas() 136 if err != nil { 137 return nil, err 138 } 139 actionCtx.IntrinsicGas = intrinsicGas 140 actionCtx.Nonce = selp.Nonce() 141 142 return protocol.WithActionCtx(ctx, actionCtx), nil 143 } 144 145 func (ws *workingSet) runAction( 146 ctx context.Context, 147 selp *action.SealedEnvelope, 148 ) (*action.Receipt, error) { 149 actCtx := protocol.MustGetActionCtx(ctx) 150 if protocol.MustGetBlockCtx(ctx).GasLimit < actCtx.IntrinsicGas { 151 return nil, action.ErrGasLimit 152 } 153 // Reject execution of chainID not equal the node's chainID 154 if !action.IsSystemAction(selp) { 155 if err := validateChainID(ctx, selp.ChainID()); err != nil { 156 return nil, err 157 } 158 } 159 // for replay tx, check against deployer whitelist 160 g := genesis.MustExtractGenesisContext(ctx) 161 if selp.Encoding() == uint32(iotextypes.Encoding_ETHEREUM_UNPROTECTED) && !g.IsDeployerWhitelisted(selp.SenderAddress()) { 162 return nil, errors.Errorf("replay deployer %v not whitelisted", selp.SenderAddress().String()) 163 } 164 // Handle action 165 reg, ok := protocol.GetRegistry(ctx) 166 if !ok { 167 return nil, errors.New("protocol is empty") 168 } 169 selpHash, err := selp.Hash() 170 if err != nil { 171 return nil, errors.Wrapf(err, "Failed to get hash") 172 } 173 defer ws.ResetSnapshots() 174 if err := ws.freshAccountConversion(ctx, &actCtx); err != nil { 175 return nil, err 176 } 177 for _, actionHandler := range reg.All() { 178 receipt, err := actionHandler.Handle(ctx, selp.Action(), ws) 179 if err != nil { 180 return nil, errors.Wrapf( 181 err, 182 "error when action %x mutates states", 183 selpHash, 184 ) 185 } 186 if receipt != nil { 187 return receipt, nil 188 } 189 } 190 return nil, errors.New("receipt is empty") 191 } 192 193 func validateChainID(ctx context.Context, chainID uint32) error { 194 blkChainCtx := protocol.MustGetBlockchainCtx(ctx) 195 featureCtx := protocol.MustGetFeatureCtx(ctx) 196 if featureCtx.AllowCorrectChainIDOnly && chainID != blkChainCtx.ChainID { 197 return errors.Wrapf(action.ErrChainID, "expecting %d, got %d", blkChainCtx.ChainID, chainID) 198 } 199 if featureCtx.AllowCorrectDefaultChainID && (chainID != blkChainCtx.ChainID && chainID != 0) { 200 return errors.Wrapf(action.ErrChainID, "expecting %d, got %d", blkChainCtx.ChainID, chainID) 201 } 202 return nil 203 } 204 205 func (ws *workingSet) finalize() error { 206 if ws.finalized { 207 return errors.New("Cannot finalize a working set twice") 208 } 209 if err := ws.store.Finalize(ws.height); err != nil { 210 return err 211 } 212 ws.finalized = true 213 214 return nil 215 } 216 217 func (ws *workingSet) Snapshot() int { 218 return ws.store.Snapshot() 219 } 220 221 func (ws *workingSet) Revert(snapshot int) error { 222 return ws.store.RevertSnapshot(snapshot) 223 } 224 225 func (ws *workingSet) ResetSnapshots() { 226 ws.store.ResetSnapshots() 227 } 228 229 // freshAccountConversion happens between UseZeroNonceForFreshAccount height 230 // and RefactorFreshAccountConversion height 231 func (ws *workingSet) freshAccountConversion(ctx context.Context, actCtx *protocol.ActionCtx) error { 232 // check legacy fresh account conversion 233 if protocol.MustGetFeatureCtx(ctx).UseZeroNonceForFreshAccount && 234 !protocol.MustGetFeatureCtx(ctx).RefactorFreshAccountConversion { 235 sender, err := accountutil.AccountState(ctx, ws, actCtx.Caller) 236 if err != nil { 237 return errors.Wrapf(err, "failed to get the confirmed nonce of sender %s", actCtx.Caller.String()) 238 } 239 if sender.ConvertFreshAccountToZeroNonceType(actCtx.Nonce) { 240 if err = accountutil.StoreAccount(ws, actCtx.Caller, sender); err != nil { 241 return errors.Wrapf(err, "failed to store converted sender %s", actCtx.Caller.String()) 242 } 243 } 244 } 245 return nil 246 } 247 248 // Commit persists all changes in RunActions() into the DB 249 func (ws *workingSet) Commit(ctx context.Context) error { 250 if err := protocolPreCommit(ctx, ws); err != nil { 251 return err 252 } 253 if err := ws.store.Commit(); err != nil { 254 return err 255 } 256 if err := protocolCommit(ctx, ws); err != nil { 257 // TODO (zhi): wrap the error and eventually panic it in caller side 258 return err 259 } 260 ws.Reset() 261 return nil 262 } 263 264 // State pulls a state from DB 265 func (ws *workingSet) State(s interface{}, opts ...protocol.StateOption) (uint64, error) { 266 _stateDBMtc.WithLabelValues("get").Inc() 267 cfg, err := processOptions(opts...) 268 if err != nil { 269 return ws.height, err 270 } 271 value, err := ws.store.Get(cfg.Namespace, cfg.Key) 272 if err != nil { 273 return ws.height, err 274 } 275 return ws.height, state.Deserialize(s, value) 276 } 277 278 func (ws *workingSet) States(opts ...protocol.StateOption) (uint64, state.Iterator, error) { 279 cfg, err := processOptions(opts...) 280 if err != nil { 281 return ws.height, nil, err 282 } 283 if cfg.Key != nil { 284 return 0, nil, errors.Wrap(ErrNotSupported, "Read states with key option has not been implemented yet") 285 } 286 values, err := ws.store.States(cfg.Namespace, cfg.Keys) 287 if err != nil { 288 return 0, nil, err 289 } 290 return ws.height, state.NewIterator(values), nil 291 } 292 293 // PutState puts a state into DB 294 func (ws *workingSet) PutState(s interface{}, opts ...protocol.StateOption) (uint64, error) { 295 _stateDBMtc.WithLabelValues("put").Inc() 296 cfg, err := processOptions(opts...) 297 if err != nil { 298 return ws.height, err 299 } 300 ss, err := state.Serialize(s) 301 if err != nil { 302 return ws.height, errors.Wrapf(err, "failed to convert account %v to bytes", s) 303 } 304 return ws.height, ws.store.Put(cfg.Namespace, cfg.Key, ss) 305 } 306 307 // DelState deletes a state from DB 308 func (ws *workingSet) DelState(opts ...protocol.StateOption) (uint64, error) { 309 _stateDBMtc.WithLabelValues("delete").Inc() 310 cfg, err := processOptions(opts...) 311 if err != nil { 312 return ws.height, err 313 } 314 return ws.height, ws.store.Delete(cfg.Namespace, cfg.Key) 315 } 316 317 // ReadView reads the view 318 func (ws *workingSet) ReadView(name string) (interface{}, error) { 319 return ws.store.ReadView(name) 320 } 321 322 // WriteView writeback the view to factory 323 func (ws *workingSet) WriteView(name string, v interface{}) error { 324 return ws.store.WriteView(name, v) 325 } 326 327 func (ws *workingSet) ProtocolDirty(name string) bool { 328 return ws.dock.ProtocolDirty(name) 329 } 330 331 func (ws *workingSet) Load(name, key string, v interface{}) error { 332 return ws.dock.Load(name, key, v) 333 } 334 335 func (ws *workingSet) Unload(name, key string, v interface{}) error { 336 return ws.dock.Unload(name, key, v) 337 } 338 339 func (ws *workingSet) Reset() { 340 ws.dock.Reset() 341 } 342 343 // createGenesisStates initialize the genesis states 344 func (ws *workingSet) CreateGenesisStates(ctx context.Context) error { 345 if reg, ok := protocol.GetRegistry(ctx); ok { 346 for _, p := range reg.All() { 347 if gsc, ok := p.(protocol.GenesisStateCreator); ok { 348 if err := gsc.CreateGenesisStates(ctx, ws); err != nil { 349 return errors.Wrap(err, "failed to create genesis states for protocol") 350 } 351 } 352 } 353 } 354 355 return ws.finalize() 356 } 357 358 func (ws *workingSet) validateNonce(ctx context.Context, blk *block.Block) error { 359 accountNonceMap := make(map[string][]uint64) 360 for _, selp := range blk.Actions { 361 caller := selp.SenderAddress() 362 if caller == nil { 363 return errors.New("failed to get address") 364 } 365 appendActionIndex(accountNonceMap, caller.String(), selp.Nonce()) 366 } 367 return ws.checkNonceContinuity(ctx, accountNonceMap) 368 } 369 370 func (ws *workingSet) validateNonceSkipSystemAction(ctx context.Context, blk *block.Block) error { 371 accountNonceMap := make(map[string][]uint64) 372 for _, selp := range blk.Actions { 373 if action.IsSystemAction(selp) { 374 continue 375 } 376 377 caller := selp.SenderAddress() 378 if caller == nil { 379 return errors.New("failed to get address") 380 } 381 srcAddr := caller.String() 382 if _, ok := accountNonceMap[srcAddr]; !ok { 383 accountNonceMap[srcAddr] = make([]uint64, 0) 384 } 385 accountNonceMap[srcAddr] = append(accountNonceMap[srcAddr], selp.Nonce()) 386 } 387 return ws.checkNonceContinuity(ctx, accountNonceMap) 388 } 389 390 func (ws *workingSet) checkNonceContinuity(ctx context.Context, accountNonceMap map[string][]uint64) error { 391 var ( 392 pendingNonce uint64 393 useZeroNonce = protocol.MustGetFeatureCtx(ctx).UseZeroNonceForFreshAccount 394 ) 395 // Verify each account's Nonce 396 for srcAddr, receivedNonces := range accountNonceMap { 397 addr, _ := address.FromString(srcAddr) 398 confirmedState, err := accountutil.AccountState(ctx, ws, addr) 399 if err != nil { 400 return errors.Wrapf(err, "failed to get the confirmed nonce of address %s", srcAddr) 401 } 402 sort.Slice(receivedNonces, func(i, j int) bool { return receivedNonces[i] < receivedNonces[j] }) 403 if useZeroNonce { 404 pendingNonce = confirmedState.PendingNonceConsideringFreshAccount() 405 } else { 406 pendingNonce = confirmedState.PendingNonce() 407 } 408 for i, nonce := range receivedNonces { 409 if nonce != pendingNonce+uint64(i) { 410 return errors.Wrapf( 411 action.ErrNonceTooHigh, 412 "the %d-th nonce %d of address %s (init pending nonce %d) is not continuously increasing", 413 i, 414 nonce, 415 srcAddr, 416 pendingNonce, 417 ) 418 } 419 } 420 } 421 return nil 422 } 423 424 func (ws *workingSet) Process(ctx context.Context, actions []*action.SealedEnvelope) error { 425 return ws.process(ctx, actions) 426 } 427 428 func (ws *workingSet) process(ctx context.Context, actions []*action.SealedEnvelope) error { 429 if err := ws.validate(ctx); err != nil { 430 return err 431 } 432 433 reg := protocol.MustGetRegistry(ctx) 434 for _, act := range actions { 435 ctxWithActionContext, err := withActionCtx(ctx, act) 436 if err != nil { 437 return err 438 } 439 for _, p := range reg.All() { 440 if validator, ok := p.(protocol.ActionValidator); ok { 441 if err := validator.Validate(ctxWithActionContext, act.Action(), ws); err != nil { 442 return err 443 } 444 } 445 } 446 } 447 for _, p := range reg.All() { 448 if pp, ok := p.(protocol.PreStatesCreator); ok { 449 if err := pp.CreatePreStates(ctx, ws); err != nil { 450 return err 451 } 452 } 453 } 454 455 receipts, err := ws.runActions(ctx, actions) 456 if err != nil { 457 return err 458 } 459 ws.receipts = receipts 460 return ws.finalize() 461 } 462 463 func (ws *workingSet) generateSystemActions(ctx context.Context) ([]action.Envelope, error) { 464 reg := protocol.MustGetRegistry(ctx) 465 postSystemActions := []action.Envelope{} 466 for _, p := range reg.All() { 467 if psc, ok := p.(protocol.PostSystemActionsCreator); ok { 468 elps, err := psc.CreatePostSystemActions(ctx, ws) 469 if err != nil { 470 return nil, err 471 } 472 postSystemActions = append(postSystemActions, elps...) 473 } 474 } 475 return postSystemActions, nil 476 } 477 478 // validateSystemActionLayout verify whether the post system actions are appended tail 479 func (ws *workingSet) validateSystemActionLayout(ctx context.Context, actions []*action.SealedEnvelope) error { 480 postSystemActions, err := ws.generateSystemActions(ctx) 481 if err != nil { 482 return err 483 } 484 // system actions should be at the end of the action list, and they should be continuous 485 expectedStartIdx := len(actions) - len(postSystemActions) 486 sysActCnt := 0 487 for i := range actions { 488 if action.IsSystemAction(actions[i]) { 489 if i != expectedStartIdx+sysActCnt { 490 return errors.Wrapf(errInvalidSystemActionLayout, "the %d-th action should not be a system action", i) 491 } 492 if actions[i].Envelope.Proto().String() != postSystemActions[sysActCnt].Proto().String() { 493 return errors.Wrapf(errInvalidSystemActionLayout, "the %d-th action is not the expected system action", i) 494 } 495 sysActCnt++ 496 } 497 } 498 if sysActCnt != len(postSystemActions) { 499 return errors.Wrapf(errInvalidSystemActionLayout, "the number of system actions is incorrect, expected %d, got %d", len(postSystemActions), sysActCnt) 500 } 501 return nil 502 } 503 504 func (ws *workingSet) pickAndRunActions( 505 ctx context.Context, 506 ap actpool.ActPool, 507 postSystemActions []*action.SealedEnvelope, 508 allowedBlockGasResidue uint64, 509 ) ([]*action.SealedEnvelope, error) { 510 err := ws.validate(ctx) 511 if err != nil { 512 return nil, err 513 } 514 receipts := make([]*action.Receipt, 0) 515 executedActions := make([]*action.SealedEnvelope, 0) 516 reg := protocol.MustGetRegistry(ctx) 517 518 for _, p := range reg.All() { 519 if pp, ok := p.(protocol.PreStatesCreator); ok { 520 if err := pp.CreatePreStates(ctx, ws); err != nil { 521 return nil, err 522 } 523 } 524 } 525 526 // initial action iterator 527 blkCtx := protocol.MustGetBlockCtx(ctx) 528 ctxWithBlockContext := ctx 529 if ap != nil { 530 actionIterator := actioniterator.NewActionIterator(ap.PendingActionMap()) 531 for { 532 nextAction, ok := actionIterator.Next() 533 if !ok { 534 break 535 } 536 if nextAction.GasLimit() > blkCtx.GasLimit { 537 actionIterator.PopAccount() 538 continue 539 } 540 actionCtx, err := withActionCtx(ctxWithBlockContext, nextAction) 541 if err == nil { 542 for _, p := range reg.All() { 543 if validator, ok := p.(protocol.ActionValidator); ok { 544 if err = validator.Validate(actionCtx, nextAction.Action(), ws); err != nil { 545 break 546 } 547 } 548 } 549 } 550 if err != nil { 551 caller := nextAction.SenderAddress() 552 if caller == nil { 553 return nil, errors.New("failed to get address") 554 } 555 ap.DeleteAction(caller) 556 actionIterator.PopAccount() 557 continue 558 } 559 receipt, err := ws.runAction(actionCtx, nextAction) 560 switch errors.Cause(err) { 561 case nil: 562 // do nothing 563 case action.ErrChainID: 564 continue 565 case action.ErrGasLimit: 566 actionIterator.PopAccount() 567 continue 568 default: 569 nextActionHash, hashErr := nextAction.Hash() 570 if hashErr != nil { 571 return nil, errors.Wrapf(hashErr, "Failed to get hash for %x", nextActionHash) 572 } 573 return nil, errors.Wrapf(err, "Failed to update state changes for selp %x", nextActionHash) 574 } 575 blkCtx.GasLimit -= receipt.GasConsumed 576 ctxWithBlockContext = protocol.WithBlockCtx(ctx, blkCtx) 577 receipts = append(receipts, receipt) 578 executedActions = append(executedActions, nextAction) 579 580 // To prevent loop all actions in act_pool, we stop processing action when remaining gas is below 581 // than certain threshold 582 if blkCtx.GasLimit < allowedBlockGasResidue { 583 break 584 } 585 } 586 } 587 588 for _, selp := range postSystemActions { 589 actionCtx, err := withActionCtx(ctxWithBlockContext, selp) 590 if err != nil { 591 return nil, err 592 } 593 receipt, err := ws.runAction(actionCtx, selp) 594 if err != nil { 595 return nil, err 596 } 597 receipts = append(receipts, receipt) 598 executedActions = append(executedActions, selp) 599 } 600 if protocol.MustGetFeatureCtx(ctx).CorrectTxLogIndex { 601 updateReceiptIndex(receipts) 602 } 603 ws.receipts = receipts 604 605 return executedActions, ws.finalize() 606 } 607 608 func updateReceiptIndex(receipts []*action.Receipt) { 609 var txIndex, logIndex uint32 610 for _, r := range receipts { 611 logIndex = r.UpdateIndex(txIndex, logIndex) 612 txIndex++ 613 } 614 } 615 616 func (ws *workingSet) ValidateBlock(ctx context.Context, blk *block.Block) error { 617 if protocol.MustGetFeatureCtx(ctx).SkipSystemActionNonce { 618 if err := ws.validateNonceSkipSystemAction(ctx, blk); err != nil { 619 return errors.Wrap(err, "failed to validate nonce") 620 } 621 } else { 622 if err := ws.validateNonce(ctx, blk); err != nil { 623 return errors.Wrap(err, "failed to validate nonce") 624 } 625 } 626 if protocol.MustGetFeatureCtx(ctx).ValidateSystemAction { 627 if err := ws.validateSystemActionLayout(ctx, blk.RunnableActions().Actions()); err != nil { 628 return err 629 } 630 } 631 632 if err := ws.process(ctx, blk.RunnableActions().Actions()); err != nil { 633 log.L().Error("Failed to update state.", zap.Uint64("height", ws.height), zap.Error(err)) 634 return err 635 } 636 637 digest, err := ws.digest() 638 if err != nil { 639 return err 640 } 641 if !blk.VerifyDeltaStateDigest(digest) { 642 return errors.Wrapf(block.ErrDeltaStateMismatch, "digest in block '%x' vs digest in workingset '%x'", blk.DeltaStateDigest(), digest) 643 } 644 receiptRoot := calculateReceiptRoot(ws.receipts) 645 if !blk.VerifyReceiptRoot(receiptRoot) { 646 return errors.Wrapf(block.ErrReceiptRootMismatch, "receipt root in block '%x' vs receipt root in workingset '%x'", blk.ReceiptRoot(), receiptRoot) 647 } 648 649 return nil 650 } 651 652 func (ws *workingSet) CreateBuilder( 653 ctx context.Context, 654 ap actpool.ActPool, 655 postSystemActions []*action.SealedEnvelope, 656 allowedBlockGasResidue uint64, 657 ) (*block.Builder, error) { 658 actions, err := ws.pickAndRunActions(ctx, ap, postSystemActions, allowedBlockGasResidue) 659 if err != nil { 660 return nil, err 661 } 662 663 ra := block.NewRunnableActionsBuilder(). 664 AddActions(actions...). 665 Build() 666 667 blkCtx := protocol.MustGetBlockCtx(ctx) 668 bcCtx := protocol.MustGetBlockchainCtx(ctx) 669 prevBlkHash := bcCtx.Tip.Hash 670 digest, err := ws.digest() 671 if err != nil { 672 return nil, errors.Wrap(err, "failed to get digest") 673 } 674 675 blkBuilder := block.NewBuilder(ra). 676 SetHeight(blkCtx.BlockHeight). 677 SetTimestamp(blkCtx.BlockTimeStamp). 678 SetPrevBlockHash(prevBlkHash). 679 SetDeltaStateDigest(digest). 680 SetReceipts(ws.receipts). 681 SetReceiptRoot(calculateReceiptRoot(ws.receipts)). 682 SetLogsBloom(calculateLogsBloom(ctx, ws.receipts)) 683 return blkBuilder, nil 684 }