9
9
"github.com/crytic/medusa/chain/config"
10
10
"github.com/ethereum/go-ethereum/core/rawdb"
11
11
"github.com/ethereum/go-ethereum/core/tracing"
12
+ "github.com/ethereum/go-ethereum/crypto"
13
+ "github.com/ethereum/go-ethereum/eth/tracers"
12
14
"github.com/ethereum/go-ethereum/triedb"
13
15
"github.com/ethereum/go-ethereum/triedb/hashdb"
14
16
"github.com/holiman/uint256"
@@ -84,7 +86,7 @@ type TestChain struct {
84
86
// NewTestChain creates a simulated Ethereum backend used for testing, or returns an error if one occurred.
85
87
// This creates a test chain with a test chain configuration and the provided genesis allocation and config.
86
88
// If a nil config is provided, a default one is used.
87
- func NewTestChain (genesisAlloc core .GenesisAlloc , testChainConfig * config.TestChainConfig ) (* TestChain , error ) {
89
+ func NewTestChain (genesisAlloc types .GenesisAlloc , testChainConfig * config.TestChainConfig ) (* TestChain , error ) {
88
90
// Copy our chain config, so it is not shared across chains.
89
91
chainConfig , err := utils .CopyChainConfig (params .TestChainConfig )
90
92
if err != nil {
@@ -143,7 +145,7 @@ func NewTestChain(genesisAlloc core.GenesisAlloc, testChainConfig *config.TestCh
143
145
return nil , err
144
146
}
145
147
for _ , cheatContract := range cheatContracts {
146
- genesisDefinition .Alloc [cheatContract .address ] = core. GenesisAccount {
148
+ genesisDefinition .Alloc [cheatContract .address ] = types. Account {
147
149
Balance : big .NewInt (0 ),
148
150
Code : []byte {0xFF },
149
151
}
@@ -251,7 +253,7 @@ func (t *TestChain) Clone(onCreateFunc func(chain *TestChain) error) (*TestChain
251
253
// Now add each transaction/message to it.
252
254
messages := t .blocks [i ].Messages
253
255
for j := 0 ; j < len (messages ); j ++ {
254
- err = targetChain .PendingBlockAddTx (messages [j ])
256
+ err = targetChain .PendingBlockAddTx (messages [j ], nil )
255
257
if err != nil {
256
258
return nil , err
257
259
}
@@ -561,7 +563,7 @@ func (t *TestChain) CallContract(msg *core.Message, state *state.StateDB, additi
561
563
}
562
564
563
565
// Obtain our state snapshot to revert any changes after our call
564
- // snapshot := state.Snapshot()
566
+ snapshot := state .Snapshot ()
565
567
566
568
// Set infinite balance to the fake caller account
567
569
state .AddBalance (msg .From , uint256 .MustFromBig (math .MaxBig256 ), tracing .BalanceChangeUnspecified )
@@ -585,19 +587,57 @@ func (t *TestChain) CallContract(msg *core.Message, state *state.StateDB, additi
585
587
})
586
588
t .evm = evm
587
589
590
+ tx := utils .MessageToTransaction (msg )
588
591
if evm .Config .Tracer != nil && evm .Config .Tracer .OnTxStart != nil {
589
- evm .Config .Tracer .OnTxStart (evm .GetVMContext (), utils . MessageToTransaction ( msg ) , msg .From )
592
+ evm .Config .Tracer .OnTxStart (evm .GetVMContext (), tx , msg .From )
590
593
}
591
594
// Fund the gas pool, so it can execute endlessly (no block gas limit).
592
595
gasPool := new (core.GasPool ).AddGas (math .MaxUint64 )
593
596
594
597
// Perform our state transition to obtain the result.
595
- res , err := core .NewStateTransition (evm , msg , gasPool ). TransitionDb ( )
598
+ msgResult , err := core .ApplyMessage (evm , msg , gasPool )
596
599
597
600
// Revert to our state snapshot to undo any changes.
598
- // state.RevertToSnapshot(snapshot)
601
+ if err != nil {
602
+ state .RevertToSnapshot (snapshot )
603
+ }
604
+
605
+ // Receipt:
606
+ var root []byte
607
+ if t .chainConfig .IsByzantium (blockContext .BlockNumber ) {
608
+ t .state .Finalise (true )
609
+ } else {
610
+ root = state .IntermediateRoot (t .chainConfig .IsEIP158 (blockContext .BlockNumber )).Bytes ()
611
+ }
599
612
600
- return res , err
613
+ // Create a new receipt for the transaction, storing the intermediate root and
614
+ // gas used by the tx.
615
+ receipt := & types.Receipt {Type : tx .Type (), PostState : root , CumulativeGasUsed : msgResult .UsedGas }
616
+ if msgResult .Failed () {
617
+ receipt .Status = types .ReceiptStatusFailed
618
+ } else {
619
+ receipt .Status = types .ReceiptStatusSuccessful
620
+ }
621
+ receipt .TxHash = tx .Hash ()
622
+ receipt .GasUsed = msgResult .UsedGas
623
+
624
+ // If the transaction created a contract, store the creation address in the receipt.
625
+ if msg .To == nil {
626
+ receipt .ContractAddress = crypto .CreateAddress (evm .TxContext .Origin , tx .Nonce ())
627
+ }
628
+
629
+ // Set the receipt logs and create the bloom filter.
630
+ receipt .Logs = t .state .GetLogs (tx .Hash (), blockContext .BlockNumber .Uint64 (), blockContext .GetHash (blockContext .BlockNumber .Uint64 ()))
631
+ receipt .Bloom = types .CreateBloom (types.Receipts {receipt })
632
+ receipt .TransactionIndex = uint (0 )
633
+
634
+ if evm .Config .Tracer != nil {
635
+ if evm .Config .Tracer .OnTxEnd != nil {
636
+ evm .Config .Tracer .OnTxEnd (receipt , nil )
637
+ }
638
+ }
639
+
640
+ return msgResult , err
601
641
}
602
642
603
643
// PendingBlock describes the current pending block which is being constructed and awaiting commitment to the chain.
@@ -701,16 +741,19 @@ func (t *TestChain) PendingBlockCreateWithParameters(blockNumber uint64, blockTi
701
741
702
742
// PendingBlockAddTx takes a message (internal txs) and adds it to the current pending block, updating the header
703
743
// with relevant execution information. If a pending block was not created, an error is returned.
704
- // Returns the constructed block, or an error if one occurred.
705
- func (t * TestChain ) PendingBlockAddTx (message * core.Message ) error {
744
+ // Returns an error if one occurred.
745
+ func (t * TestChain ) PendingBlockAddTx (message * core.Message , getTracerFn func (txIndex int , txHash common.Hash ) * tracers.Tracer ) error {
746
+ if getTracerFn == nil {
747
+ getTracerFn = func (txIndex int , txHash common.Hash ) * tracers.Tracer {
748
+ return t .transactionTracerRouter .NativeTracer .Tracer
749
+ }
750
+ }
751
+
706
752
// If we don't have a pending block, return an error
707
753
if t .pendingBlock == nil {
708
754
return errors .New ("could not add tx to the chain's pending block because no pending block was created" )
709
755
}
710
756
711
- // Obtain our state root hash prior to execution.
712
- // previousStateRoot := t.pendingBlock.Header.Root
713
-
714
757
// Create a gas pool indicating how much gas can be spent executing the transaction.
715
758
gasPool := new (core.GasPool ).AddGas (t .pendingBlock .Header .GasLimit - t .pendingBlock .Header .GasUsed )
716
759
@@ -721,17 +764,25 @@ func (t *TestChain) PendingBlockAddTx(message *core.Message) error {
721
764
// TODO reuse
722
765
blockContext := newTestChainBlockContext (t , t .pendingBlock .Header )
723
766
724
- // Create our EVM instance.
725
- evm := vm .NewEVM (blockContext , core .NewEVMTxContext (message ), t .state , t .chainConfig , vm.Config {
767
+ vmConfig := vm.Config {
726
768
//Debug: true,
727
- Tracer : t .transactionTracerRouter .NativeTracer .Hooks ,
728
769
NoBaseFee : true ,
729
770
ConfigExtensions : t .vmConfigExtensions ,
730
- })
731
- t .evm = evm
771
+ }
772
+
773
+ tracer := getTracerFn (len (t .pendingBlock .Messages ), tx .Hash ())
774
+ if tracer != nil {
775
+ vmConfig .Tracer = tracer .Hooks
776
+ }
732
777
733
778
t .state .SetTxContext (tx .Hash (), len (t .pendingBlock .Messages ))
734
779
780
+ // Create our EVM instance.
781
+ evm := vm .NewEVM (blockContext , core .NewEVMTxContext (message ), t .state , t .chainConfig , vmConfig )
782
+
783
+ // Set our EVM instance for the test chain in order for cheatcodes to access EVM interpreter's block context.
784
+ t .evm = evm
785
+
735
786
if evm .Config .Tracer != nil && evm .Config .Tracer .OnTxStart != nil {
736
787
evm .Config .Tracer .OnTxStart (evm .GetVMContext (), tx , message .From )
737
788
}
@@ -934,11 +985,11 @@ func (t *TestChain) emitContractChangeEvents(reverting bool, messageResults ...*
934
985
Contract : deploymentChange .Contract ,
935
986
})
936
987
} else if deploymentChange .Destroyed {
937
- err = t .Events .ContractDeploymentAddedEventEmitter .Publish (ContractDeploymentsAddedEvent {
938
- Chain : t ,
939
- Contract : deploymentChange .Contract ,
940
- DynamicDeployment : deploymentChange .DynamicCreation ,
941
- })
988
+ // err = t.Events.ContractDeploymentAddedEventEmitter.Publish(ContractDeploymentsAddedEvent{
989
+ // Chain: t,
990
+ // Contract: deploymentChange.Contract,
991
+ // DynamicDeployment: deploymentChange.DynamicCreation,
992
+ // })
942
993
}
943
994
if err != nil {
944
995
return err
0 commit comments