@@ -24,6 +24,7 @@ import {
24
24
divCeil ,
25
25
evmmaxMemoryGasCost ,
26
26
isPowerOfTwo ,
27
+ makeEVMMAXArithGasFunc ,
27
28
maxCallGas ,
28
29
setLengthLeftStorage ,
29
30
subMemUsage ,
@@ -33,7 +34,13 @@ import {
33
34
34
35
import type { Common } from '@ethereumjs/common'
35
36
import type { Address } from '@ethereumjs/util'
36
- import { MAX_ALLOC_SIZE , SETMODX_ODD_MODULUS_COST } from '../evmmax/constants.js'
37
+ import {
38
+ ADD_OR_SUB_COST ,
39
+ MAX_ALLOC_SIZE ,
40
+ MULMODX_COST ,
41
+ SETMODX_ODD_MODULUS_COST ,
42
+ } from '../evmmax/index.ts'
43
+ import { add64 , mul64 } from '../evmmax/util.ts'
37
44
import type { RunState } from '../interpreter.ts'
38
45
39
46
const EXTCALL_TARGET_MAX = BigInt ( 2 ) ** BigInt ( 8 * 20 ) - BigInt ( 1 )
@@ -787,7 +794,7 @@ export const dynamicGasHandlers: Map<number, AsyncDynamicGasHandler | SyncDynami
787
794
trap ( 'one or more parameters overflows 64 bits' )
788
795
}
789
796
if ( runState . evmmaxState . getAlloced ( ) . get ( Number ( modId ) ) !== undefined ) {
790
- return 0n
797
+ return gas
791
798
}
792
799
if ( modSize > 96n ) {
793
800
trap ( 'modulus cannot exceed 768 bits in width' )
@@ -809,44 +816,104 @@ export const dynamicGasHandlers: Map<number, AsyncDynamicGasHandler | SyncDynami
809
816
const memCost = evmmaxMemoryGasCost ( runState , common , allocSize , 0n , 0n ) // TODO should I be setting length and offset to 0?
810
817
const modBytes = runState . memory . read ( Number ( modOffset ) , Number ( modSize ) )
811
818
if ( ! isPowerOfTwo ( bytesToBigInt ( modBytes ) ) ) {
812
- return BigInt ( precompCost ) + memCost
819
+ return ( gas += BigInt ( precompCost ) + memCost )
813
820
}
814
- return memCost
821
+ return gas + memCost
815
822
} ,
816
823
] ,
817
824
[
818
825
/* LOADX */
819
826
0xc1 ,
820
827
async function ( runState , gas , common ) : Promise < bigint > {
821
- return 0n
828
+ const [ dst , src , count ] = runState . stack . peek ( 3 )
829
+
830
+ if ( ! isUint64 ( src ) || src >= runState . evmmaxState . getActive ( ) . getNumElems ( ) ) {
831
+ trap ( 'src index out of bounds' )
832
+ }
833
+ if ( ! isUint64 ( count ) || count >= runState . evmmaxState . getActive ( ) . getNumElems ( ) ) {
834
+ trap ( 'count must be less than number of field elements in the active space' )
835
+ }
836
+ const [ last1 , overflow1 ] = add64 ( src , count , 0n )
837
+ if ( overflow1 !== 0n || last1 > runState . evmmaxState . getActive ( ) . getNumElems ( ) ) {
838
+ trap ( 'out of bounds copy source' )
839
+ }
840
+ if ( ! isUint64 ( dst ) ) {
841
+ trap ( 'destination of copy out of bounds' )
842
+ }
843
+
844
+ const [ loadSize , overflow2 ] = mul64 (
845
+ count ,
846
+ BigInt ( runState . evmmaxState . getActive ( ) . getElemSize ( ) ) ,
847
+ )
848
+ if ( overflow2 !== 0n ) {
849
+ trap ( 'overflow' )
850
+ }
851
+ const [ last2 , overflow3 ] = add64 ( dst , loadSize , 0n )
852
+ if ( overflow3 !== 0n || last2 > runState . memoryWordCount ) {
853
+ trap ( 'out of bounds destination' )
854
+ }
855
+
856
+ if ( runState . evmmaxState . getActive ( ) . isModulusBinary ) {
857
+ return gas + loadSize * common . param ( 'copyGas' ) // TODO check if this translates from go: toWordSize(storeSize) * params.copyGas
858
+ } else {
859
+ return (
860
+ gas +
861
+ count *
862
+ BigInt ( MULMODX_COST [ Number ( runState . evmmaxState . getActive ( ) . getElemSize ( ) / 8 ) - 1 ] )
863
+ )
864
+ }
822
865
} ,
823
866
] ,
824
867
[
825
868
/* STOREX */
826
869
0xc2 ,
827
870
async function ( runState , gas , common ) : Promise < bigint > {
828
- return 0n
871
+ const [ dst , src , count ] = runState . stack . peek ( 3 )
872
+
873
+ if ( ! isUint64 ( src ) || src >= runState . memoryWordCount ) {
874
+ trap ( 'src index out of bounds' )
875
+ }
876
+ if ( ! isUint64 ( dst ) || dst >= runState . evmmaxState . getActive ( ) . getNumElems ( ) ) {
877
+ trap ( 'destination of copy out of bounds' )
878
+ }
879
+ if ( ! isUint64 ( count ) || count >= runState . evmmaxState . getActive ( ) . getNumElems ( ) ) {
880
+ trap ( 'count must be less than number of field elements in the active space' )
881
+ }
882
+ const storeSize = count * runState . evmmaxState . getActive ( ) . getNumElems ( )
883
+ if ( src + storeSize > runState . memoryWordCount ) {
884
+ trap ( 'source of copy out of bounds of EVM memory' )
885
+ }
886
+
887
+ if ( runState . evmmaxState . getActive ( ) . isModulusBinary ) {
888
+ return gas + storeSize * common . param ( 'copyGas' ) // TODO check if this translates from go: toWordSize(storeSize) * params.copyGas
889
+ } else {
890
+ return (
891
+ gas +
892
+ count *
893
+ BigInt ( MULMODX_COST [ Number ( runState . evmmaxState . getActive ( ) . getElemSize ( ) / 8 ) - 1 ] )
894
+ )
895
+ }
829
896
} ,
830
897
] ,
831
898
[
832
899
/* ADDMODX */
833
900
0xc3 ,
834
901
async function ( runState , gas , common ) : Promise < bigint > {
835
- return 0n
902
+ return makeEVMMAXArithGasFunc ( ADD_OR_SUB_COST ) ( runState , gas , common )
836
903
} ,
837
904
] ,
838
905
[
839
906
/* SUBMODX */
840
907
0xc4 ,
841
908
async function ( runState , gas , common ) : Promise < bigint > {
842
- return 0n
909
+ return makeEVMMAXArithGasFunc ( ADD_OR_SUB_COST ) ( runState , gas , common )
843
910
} ,
844
911
] ,
845
912
[
846
913
/* MULMODX */
847
914
0xc5 ,
848
915
async function ( runState , gas , common ) : Promise < bigint > {
849
- return 0n
916
+ return makeEVMMAXArithGasFunc ( MULMODX_COST ) ( runState , gas , common )
850
917
} ,
851
918
] ,
852
919
/* EXTCALL */
0 commit comments