@@ -598,6 +598,332 @@ func TestApplyTransactionWithEVMStateChangeHooks(t *testing.T) {
598598 }
599599}
600600
601+ func TestProcessReReadsCoinbaseOwnerPerTransactionAfterPrague (t * testing.T ) {
602+ tokenAddr := common .HexToAddress ("0x00000000000000000000000000000000000000b0" )
603+ tokensFee := map [common.Address ]* big.Int {
604+ tokenAddr : new (big.Int ).Exp (big .NewInt (10 ), big .NewInt (18 ), nil ),
605+ }
606+ testApplyTransactionCoinbaseOwnerByFork (t , tokenAddr , tokensFee , big .NewInt (0 ), func (tx * types.Transaction , receipt * types.Receipt , header * types.Header ) * big.Int {
607+ return common .GetGasFee (header .Number .Uint64 (), receipt .GasUsed )
608+ })
609+ }
610+
611+ func TestProcessKeepsCoinbaseOwnerPerBlockBeforePrague (t * testing.T ) {
612+ tokenAddr := common .HexToAddress ("0x00000000000000000000000000000000000000b0" )
613+ tokensFee := map [common.Address ]* big.Int {
614+ tokenAddr : new (big.Int ).Exp (big .NewInt (10 ), big .NewInt (18 ), nil ),
615+ }
616+ pragueBlock := new (big.Int ).Add (common .TIPTRC21Fee , big .NewInt (2 ))
617+ testProcessCoinbaseOwnerByFork (t , tokenAddr , tokensFee , pragueBlock , false , func (tx * types.Transaction , receipt * types.Receipt , header * types.Header ) * big.Int {
618+ return common .GetGasFee (header .Number .Uint64 (), receipt .GasUsed )
619+ })
620+ }
621+
622+ func TestProcessReReadsCoinbaseOwnerPerTransactionAfterPragueNativeFee (t * testing.T ) {
623+ recipient := common .HexToAddress ("0x00000000000000000000000000000000000000d0" )
624+ testApplyTransactionCoinbaseOwnerByFork (t , recipient , nil , big .NewInt (0 ), func (tx * types.Transaction , receipt * types.Receipt , header * types.Header ) * big.Int {
625+ fee := new (big.Int ).SetUint64 (receipt .GasUsed )
626+ return fee .Mul (fee , tx .EffectiveGasPrice (new (big.Int ), header .BaseFee ))
627+ })
628+ }
629+
630+ func TestProcessKeepsCoinbaseOwnerPerBlockBeforePragueNativeFee (t * testing.T ) {
631+ recipient := common .HexToAddress ("0x00000000000000000000000000000000000000d0" )
632+ pragueBlock := new (big.Int ).Add (common .TIPTRC21Fee , big .NewInt (2 ))
633+ testProcessCoinbaseOwnerByFork (t , recipient , nil , pragueBlock , false , func (tx * types.Transaction , receipt * types.Receipt , header * types.Header ) * big.Int {
634+ fee := new (big.Int ).SetUint64 (receipt .GasUsed )
635+ return fee .Mul (fee , tx .EffectiveGasPrice (new (big.Int ), header .BaseFee ))
636+ })
637+ }
638+
639+ func testProcessCoinbaseOwnerByFork (t * testing.T , recipient common.Address , tokensFee map [common.Address ]* big.Int , pragueBlock * big.Int , expectCurrentOwner bool , expectedFee func (* types.Transaction , * types.Receipt , * types.Header ) * big.Int ) {
640+ var (
641+ config = & params.ChainConfig {
642+ ChainID : big .NewInt (1 ),
643+ HomesteadBlock : big .NewInt (0 ),
644+ EIP150Block : big .NewInt (0 ),
645+ EIP155Block : big .NewInt (0 ),
646+ EIP158Block : big .NewInt (0 ),
647+ ByzantiumBlock : big .NewInt (0 ),
648+ ConstantinopleBlock : big .NewInt (0 ),
649+ PetersburgBlock : big .NewInt (0 ),
650+ IstanbulBlock : big .NewInt (0 ),
651+ BerlinBlock : big .NewInt (0 ),
652+ LondonBlock : big .NewInt (0 ),
653+ Eip1559Block : big .NewInt (0 ),
654+ PragueBlock : new (big.Int ).Set (pragueBlock ),
655+ Ethash : new (params.EthashConfig ),
656+ }
657+ chainEngine = ethash .NewFaker ()
658+ engine = noOpFinalizeEngine {Engine : chainEngine }
659+ signer = types .LatestSigner (config )
660+ testKey , _ = crypto .HexToECDSA ("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" )
661+ sender = crypto .PubkeyToAddress (testKey .PublicKey )
662+ coinbase = common .HexToAddress ("0x00000000000000000000000000000000000000c0" )
663+ owner1 = common .HexToAddress ("0x00000000000000000000000000000000000000a1" )
664+ owner2 = common .HexToAddress ("0x00000000000000000000000000000000000000a2" )
665+ blockNumber = new (big.Int ).Add (common .TIPTRC21Fee , common .Big1 )
666+ gasTipCap = new (big.Int ).Set (common .BaseFee )
667+ gasFeeCap = new (big.Int ).Mul (new (big.Int ).Set (common .BaseFee ), big .NewInt (2 ))
668+ )
669+
670+ db := rawdb .NewMemoryDatabase ()
671+ gspec := & Genesis {
672+ Config : config ,
673+ Alloc : types.GenesisAlloc {
674+ sender : {
675+ Balance : big .NewInt (1000000000000000000 ),
676+ Nonce : 0 ,
677+ },
678+ },
679+ }
680+ genesis := gspec .MustCommit (db )
681+ blockchain , _ := NewBlockChain (db , nil , gspec , chainEngine , vm.Config {})
682+ defer blockchain .Stop ()
683+
684+ statedb , err := blockchain .State ()
685+ if err != nil {
686+ t .Fatalf ("Failed to get state: %v" , err )
687+ }
688+ setCoinbaseOwner (statedb , coinbase , owner1 )
689+
690+ tx1 , err := types .SignTx (types .NewTx (& types.DynamicFeeTx {
691+ Nonce : 0 ,
692+ GasTipCap : gasTipCap ,
693+ GasFeeCap : gasFeeCap ,
694+ Gas : 21000 ,
695+ To : & recipient ,
696+ Value : big .NewInt (0 ),
697+ }), signer , testKey )
698+ if err != nil {
699+ t .Fatalf ("Failed to sign first tx: %v" , err )
700+ }
701+ tx2 , err := types .SignTx (types .NewTx (& types.DynamicFeeTx {
702+ Nonce : 1 ,
703+ GasTipCap : gasTipCap ,
704+ GasFeeCap : gasFeeCap ,
705+ Gas : 21068 ,
706+ To : & recipient ,
707+ Value : big .NewInt (0 ),
708+ Data : []byte {0x01 },
709+ }), signer , testKey )
710+ if err != nil {
711+ t .Fatalf ("Failed to sign second tx: %v" , err )
712+ }
713+
714+ header := & types.Header {
715+ ParentHash : genesis .Hash (),
716+ Coinbase : coinbase ,
717+ Difficulty : big .NewInt (0 ),
718+ GasLimit : 1000000 ,
719+ Number : blockNumber ,
720+ Time : genesis .Time () + 10 ,
721+ UncleHash : types .EmptyUncleHash ,
722+ BaseFee : new (big.Int ).Set (common .BaseFee ),
723+ }
724+ block := types .NewBlock (header , & types.Body {Transactions : types.Transactions {tx1 , tx2 }}, nil , trie .NewStackTrie (nil ))
725+
726+ txEndCalls := 0
727+ cfg := vm.Config {Tracer : & tracing.Hooks {
728+ OnTxEnd : func (receipt * types.Receipt , err error ) {
729+ txEndCalls ++
730+ if txEndCalls == 1 {
731+ setCoinbaseOwner (statedb , coinbase , owner2 )
732+ }
733+ },
734+ }}
735+
736+ processor := NewStateProcessor (config , blockchain , engine )
737+ receipts , _ , _ , err := processor .Process (block , statedb , nil , cfg , tokensFee )
738+ if err != nil {
739+ t .Fatalf ("Process failed: %v" , err )
740+ }
741+ if len (receipts ) != 2 {
742+ t .Fatalf ("expected 2 receipts, got %d" , len (receipts ))
743+ }
744+ if txEndCalls != 2 {
745+ t .Fatalf ("expected 2 OnTxEnd calls, got %d" , txEndCalls )
746+ }
747+
748+ owner1Balance := statedb .GetBalance (owner1 )
749+ owner2Balance := statedb .GetBalance (owner2 )
750+ if owner1Balance .Sign () <= 0 {
751+ t .Fatalf ("expected initial owner to receive first tx fee credit, have %v" , owner1Balance )
752+ }
753+ if expectCurrentOwner && owner2Balance .Sign () <= 0 {
754+ t .Fatalf ("expected updated owner to receive second tx fee credit, have %v" , owner2Balance )
755+ }
756+ expectedOwner1 := expectedFee (tx1 , receipts [0 ], header )
757+ expectedOwner2 := expectedFee (tx2 , receipts [1 ], header )
758+ if expectCurrentOwner {
759+ if owner1Balance .Cmp (expectedOwner1 ) != 0 {
760+ t .Fatalf ("unexpected first owner fee credit: got %v want %v" , owner1Balance , expectedOwner1 )
761+ }
762+ if owner2Balance .Cmp (expectedOwner2 ) != 0 {
763+ t .Fatalf ("unexpected updated owner fee credit: got %v want %v" , owner2Balance , expectedOwner2 )
764+ }
765+ } else {
766+ expectedOriginalOwner := new (big.Int ).Add (expectedOwner1 , expectedOwner2 )
767+ if owner1Balance .Cmp (expectedOriginalOwner ) != 0 {
768+ t .Fatalf ("unexpected pre-Prague fee credit on original owner: got %v want %v" , owner1Balance , expectedOriginalOwner )
769+ }
770+ if owner2Balance .Sign () != 0 {
771+ t .Fatalf ("expected updated owner to receive no fee credit before Prague, have %v" , owner2Balance )
772+ }
773+ }
774+
775+ totalCredited := new (big.Int ).Add (new (big.Int ).Set (owner1Balance ), owner2Balance )
776+ expectedTotal := new (big.Int ).Add (expectedOwner1 , expectedOwner2 )
777+ if totalCredited .Cmp (expectedTotal ) != 0 {
778+ t .Fatalf ("unexpected total fee credit: got %v want %v" , totalCredited , expectedTotal )
779+ }
780+ if expectCurrentOwner && owner1Balance .Cmp (expectedTotal ) == 0 {
781+ t .Fatalf ("all fee credit stayed with original owner, updated owner balance %v" , owner2Balance )
782+ }
783+ }
784+
785+ func testApplyTransactionCoinbaseOwnerByFork (t * testing.T , recipient common.Address , tokensFee map [common.Address ]* big.Int , pragueBlock * big.Int , expectedFee func (* types.Transaction , * types.Receipt , * types.Header ) * big.Int ) {
786+ var (
787+ config = & params.ChainConfig {
788+ ChainID : big .NewInt (1 ),
789+ HomesteadBlock : big .NewInt (0 ),
790+ EIP150Block : big .NewInt (0 ),
791+ EIP155Block : big .NewInt (0 ),
792+ EIP158Block : big .NewInt (0 ),
793+ ByzantiumBlock : big .NewInt (0 ),
794+ ConstantinopleBlock : big .NewInt (0 ),
795+ PetersburgBlock : big .NewInt (0 ),
796+ IstanbulBlock : big .NewInt (0 ),
797+ BerlinBlock : big .NewInt (0 ),
798+ LondonBlock : big .NewInt (0 ),
799+ Eip1559Block : big .NewInt (0 ),
800+ PragueBlock : new (big.Int ).Set (pragueBlock ),
801+ Ethash : new (params.EthashConfig ),
802+ }
803+ signer = types .LatestSigner (config )
804+ testKey , _ = crypto .HexToECDSA ("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" )
805+ sender = crypto .PubkeyToAddress (testKey .PublicKey )
806+ coinbase = common .HexToAddress ("0x00000000000000000000000000000000000000c0" )
807+ owner1 = common .HexToAddress ("0x00000000000000000000000000000000000000a1" )
808+ owner2 = common .HexToAddress ("0x00000000000000000000000000000000000000a2" )
809+ blockNumber = new (big.Int ).Add (common .TIPTRC21Fee , common .Big1 )
810+ gasTipCap = new (big.Int ).Set (common .BaseFee )
811+ gasFeeCap = new (big.Int ).Mul (new (big.Int ).Set (common .BaseFee ), big .NewInt (2 ))
812+ )
813+
814+ db := rawdb .NewMemoryDatabase ()
815+ gspec := & Genesis {
816+ Config : config ,
817+ Alloc : types.GenesisAlloc {
818+ sender : {
819+ Balance : big .NewInt (1000000000000000000 ),
820+ Nonce : 0 ,
821+ },
822+ },
823+ }
824+ genesis := gspec .MustCommit (db )
825+ blockchain , _ := NewBlockChain (db , nil , gspec , ethash .NewFaker (), vm.Config {})
826+ defer blockchain .Stop ()
827+
828+ statedb , err := blockchain .State ()
829+ if err != nil {
830+ t .Fatalf ("Failed to get state: %v" , err )
831+ }
832+ setCoinbaseOwner (statedb , coinbase , owner1 )
833+
834+ tx1 , err := types .SignTx (types .NewTx (& types.DynamicFeeTx {
835+ Nonce : 0 ,
836+ GasTipCap : gasTipCap ,
837+ GasFeeCap : gasFeeCap ,
838+ Gas : 21000 ,
839+ To : & recipient ,
840+ Value : big .NewInt (0 ),
841+ }), signer , testKey )
842+ if err != nil {
843+ t .Fatalf ("Failed to sign first tx: %v" , err )
844+ }
845+ tx2 , err := types .SignTx (types .NewTx (& types.DynamicFeeTx {
846+ Nonce : 1 ,
847+ GasTipCap : gasTipCap ,
848+ GasFeeCap : gasFeeCap ,
849+ Gas : 21068 ,
850+ To : & recipient ,
851+ Value : big .NewInt (0 ),
852+ Data : []byte {0x01 },
853+ }), signer , testKey )
854+ if err != nil {
855+ t .Fatalf ("Failed to sign second tx: %v" , err )
856+ }
857+
858+ header := & types.Header {
859+ ParentHash : genesis .Hash (),
860+ Coinbase : coinbase ,
861+ Difficulty : big .NewInt (0 ),
862+ GasLimit : 1000000 ,
863+ Number : blockNumber ,
864+ Time : genesis .Time () + 10 ,
865+ UncleHash : types .EmptyUncleHash ,
866+ BaseFee : new (big.Int ).Set (common .BaseFee ),
867+ }
868+ vmContext := NewEVMBlockContext (header , blockchain , nil )
869+ evm := vm .NewEVM (vmContext , statedb , nil , config , vm.Config {})
870+ gasPool := new (GasPool ).AddGas (header .GasLimit )
871+
872+ applyTx := func (index int , tx * types.Transaction ) * types.Receipt {
873+ var balanceFee * big.Int
874+ if tx .To () != nil {
875+ if value , ok := tokensFee [* tx .To ()]; ok {
876+ balanceFee = value
877+ }
878+ }
879+ msg , err := TransactionToMessage (tx , signer , balanceFee , header .Number , header .BaseFee )
880+ if err != nil {
881+ t .Fatalf ("Failed to build tx message: %v" , err )
882+ }
883+ statedb .SetTxContext (tx .Hash (), index )
884+ var usedGas uint64
885+ receipt , _ , _ , err := ApplyTransactionWithEVM (msg , gasPool , statedb , header .Number , header .Hash (), tx , & usedGas , evm , balanceFee , common.Address {})
886+ if err != nil {
887+ t .Fatalf ("ApplyTransactionWithEVM failed: %v" , err )
888+ }
889+ return receipt
890+ }
891+
892+ receipt1 := applyTx (0 , tx1 )
893+ setCoinbaseOwner (statedb , coinbase , owner2 )
894+ receipt2 := applyTx (1 , tx2 )
895+
896+ owner1Balance := statedb .GetBalance (owner1 )
897+ owner2Balance := statedb .GetBalance (owner2 )
898+ if owner1Balance .Sign () <= 0 {
899+ t .Fatalf ("expected initial owner to receive first tx fee credit, have %v" , owner1Balance )
900+ }
901+ if owner2Balance .Sign () <= 0 {
902+ t .Fatalf ("expected updated owner to receive second tx fee credit, have %v" , owner2Balance )
903+ }
904+ expectedOwner1 := expectedFee (tx1 , receipt1 , header )
905+ expectedOwner2 := expectedFee (tx2 , receipt2 , header )
906+ if owner1Balance .Cmp (expectedOwner1 ) != 0 {
907+ t .Fatalf ("unexpected first owner fee credit: got %v want %v" , owner1Balance , expectedOwner1 )
908+ }
909+ if owner2Balance .Cmp (expectedOwner2 ) != 0 {
910+ t .Fatalf ("unexpected updated owner fee credit: got %v want %v" , owner2Balance , expectedOwner2 )
911+ }
912+ }
913+
914+ func setCoinbaseOwner (statedb * state.StateDB , coinbase common.Address , owner common.Address ) {
915+ ownerSlot := state .GetLocMappingAtKey (coinbase .Hash (), 1 )
916+ statedb .SetState (common .MasternodeVotingSMCBinary , common .BigToHash (ownerSlot ), owner .Hash ())
917+ }
918+
919+ type noOpFinalizeEngine struct {
920+ consensus.Engine
921+ }
922+
923+ func (e noOpFinalizeEngine ) Finalize (chain consensus.ChainReader , header * types.Header , state vm.StateDB , parentState * state.StateDB , txs []* types.Transaction , uncles []* types.Header , receipts []* types.Receipt ) (* types.Block , error ) {
924+ return nil , nil
925+ }
926+
601927func TestProcessParentBlockHash (t * testing.T ) {
602928 var (
603929 chainConfig = params .MergedTestChainConfig
0 commit comments