diff --git a/go.mod b/go.mod index 0ed047a61..6422641fe 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/leanovate/gopter v0.2.11 github.com/logrusorgru/aurora/v4 v4.0.0 github.com/onflow/atree v0.12.0 + github.com/onflow/cadence-standard-transactions v0.4.0 github.com/onflow/crypto v0.25.3 github.com/onflow/fixed-point v0.1.1 github.com/rivo/uniseg v0.4.7 @@ -37,28 +38,29 @@ require ( ) require ( - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/fxamacker/circlehash v0.3.0 // indirect github.com/itchyny/timefmt-go v0.1.6 // indirect - github.com/klauspost/cpuid/v2 v2.2.0 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mattn/go-tty v0.0.3 // indirect github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect - github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/pkg/term v1.2.0-beta.2 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/zeebo/assert v1.3.0 // indirect github.com/zeebo/blake3 v0.2.4 // indirect - golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect + golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect golang.org/x/sync v0.18.0 // indirect golang.org/x/sys v0.38.0 // indirect golang.org/x/term v0.37.0 // indirect gonum.org/v1/gonum v0.16.0 // indirect - gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 31ac20b1f..0a6cba5c0 100644 --- a/go.sum +++ b/go.sum @@ -51,6 +51,8 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/bits-and-blooms/bitset v1.24.4 h1:95H15Og1clikBrKr/DuzMXkQzECs1M6hhoGXLwLQOZE= github.com/bits-and-blooms/bitset v1.24.4/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/c-bata/go-prompt v0.2.6 h1:POP+nrHE+DfLYx370bedwNhsqmpCUynWPxuHi0C5vZI= github.com/c-bata/go-prompt v0.2.6/go.mod h1:/LMAke8wD2FsNu9EXNdHxNLbd9MedkPnCdfpU9wwHfY= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -72,8 +74,11 @@ github.com/dave/dst v0.27.3/go.mod h1:jHh6EOibnHgcUW3WjKHisiooEkYwqpHLBSX1iOBhEy github.com/dave/jennifer v1.5.0 h1:HmgPN93bVDpkQyYbqhCHj5QlgvUkvEOzMyEvKLgCRrg= github.com/dave/jennifer v1.5.0/go.mod h1:4MnyiFIlZS3l5tSDn8VnzE6ffAhYBMB2SZntBsZGUok= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -199,12 +204,13 @@ github.com/k0kubun/pp/v3 v3.5.0 h1:iYNlYA5HJAJvkD4ibuf9c8y6SHM0QFhaBuCqm1zHp0w= github.com/k0kubun/pp/v3 v3.5.0/go.mod h1:5lzno5ZZeEeTV/Ky6vs3g6d1U3WarDrH8k240vMtGro= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/cpuid/v2 v2.2.0 h1:4ZexSFt8agMNzNisrsilL6RClWDC5YJnLHNIfTy4iuc= -github.com/klauspost/cpuid/v2 v2.2.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= github.com/kodova/html-to-markdown v1.0.1 h1:MJxQAnqxtss3DaPnm72DRV65HZiMQZF3DUAfEaTg+14= github.com/kodova/html-to-markdown v1.0.1/go.mod h1:NhDrT7QdSrdpezFg/0EQx9zeobCHR5oAguzrKrC6mVU= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -249,10 +255,10 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/onflow/atree v0.12.0 h1:X7/UEPyCaaEQ1gCg11KDvfyEtEeQLhtRtxMHjAiH/Co= github.com/onflow/atree v0.12.0/go.mod h1:qdZcfLQwPirHcNpLiK+2t3KAo+SAb9Si6TqurE6pykE= +github.com/onflow/cadence-standard-transactions v0.4.0 h1:xqwLwPAy3/fLL3UemtVQhfthRUfXSPKmTMd4ElM6Z1w= +github.com/onflow/cadence-standard-transactions v0.4.0/go.mod h1:OqwN4Pusj6Aj8M6kJhipttQ0qtOZ24ycDJwWJHy5WTA= github.com/onflow/crypto v0.25.3 h1:XQ3HtLsw8h1+pBN+NQ1JYM9mS2mVXTyg55OldaAIF7U= github.com/onflow/crypto v0.25.3/go.mod h1:+1igaXiK6Tjm9wQOBD1EGwW7bYWMUGKtwKJ/2QL/OWs= github.com/onflow/fixed-point v0.1.1 h1:j0jYZVO8VGyk1476alGudEg7XqCkeTVxb5ElRJRKS90= @@ -264,8 +270,9 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/term v1.2.0-beta.2 h1:L3y/h2jkuBVFdWiJvNfYfKmzcCnILw7mJWm2JQuMppw= github.com/pkg/term v1.2.0-beta.2/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -273,8 +280,9 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/schollz/progressbar/v3 v3.18.0 h1:uXdoHABRFmNIjUfte/Ex7WtuyVslrw2wVPQmCN62HpA= @@ -287,6 +295,8 @@ github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= @@ -367,8 +377,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM= -golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= +golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA= +golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -519,7 +529,6 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -715,8 +724,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -737,6 +746,8 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg= lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo= +pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw= +pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/runtime/bench_standard_transactions_test.go b/runtime/bench_standard_transactions_test.go new file mode 100644 index 000000000..56d14b31c --- /dev/null +++ b/runtime/bench_standard_transactions_test.go @@ -0,0 +1,943 @@ +/* + * Cadence - The resource-oriented smart contract programming language + * + * Copyright Flow Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package runtime_test + +import ( + "encoding/binary" + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/onflow/cadence-standard-transactions/transactions" + + "github.com/onflow/cadence" + "github.com/onflow/cadence/common" + "github.com/onflow/cadence/encoding/json" + "github.com/onflow/cadence/interpreter" + . "github.com/onflow/cadence/runtime" + "github.com/onflow/cadence/stdlib" + . "github.com/onflow/cadence/test_utils/runtime_utils" +) + +var realCryptoContract = ` +access(all) contract Crypto { + + access(all) + fun hash(_ data: [UInt8], algorithm: HashAlgorithm): [UInt8] { + return algorithm.hash(data) + } + + access(all) + fun hashWithTag(_ data: [UInt8], tag: String, algorithm: HashAlgorithm): [UInt8] { + return algorithm.hashWithTag(data, tag: tag) + } + + access(all) + struct KeyListEntry { + + access(all) + let keyIndex: Int + + access(all) + let publicKey: PublicKey + + access(all) + let hashAlgorithm: HashAlgorithm + + access(all) + let weight: UFix64 + + access(all) + let isRevoked: Bool + + init( + keyIndex: Int, + publicKey: PublicKey, + hashAlgorithm: HashAlgorithm, + weight: UFix64, + isRevoked: Bool + ) { + self.keyIndex = keyIndex + self.publicKey = publicKey + self.hashAlgorithm = hashAlgorithm + self.weight = weight + self.isRevoked = isRevoked + } + } + + access(all) + struct KeyList { + + access(self) + let entries: [KeyListEntry] + + init() { + self.entries = [] + } + + /// Adds a new key with the given weight + access(all) + fun add( + _ publicKey: PublicKey, + hashAlgorithm: HashAlgorithm, + weight: UFix64 + ): KeyListEntry { + + let keyIndex = self.entries.length + let entry = KeyListEntry( + keyIndex: keyIndex, + publicKey: publicKey, + hashAlgorithm: hashAlgorithm, + weight: weight, + isRevoked: false + ) + self.entries.append(entry) + return entry + } + + /// Returns the key at the given index, if it exists. + /// Revoked keys are always returned, but they have the isRevoked field set to true + access(all) + fun get(keyIndex: Int): KeyListEntry? { + if keyIndex >= self.entries.length { + return nil + } + + return self.entries[keyIndex] + } + + /// Marks the key at the given index revoked, but does not delete it + access(all) + fun revoke(keyIndex: Int) { + if keyIndex >= self.entries.length { + return + } + + let currentEntry = self.entries[keyIndex] + self.entries[keyIndex] = KeyListEntry( + keyIndex: currentEntry.keyIndex, + publicKey: currentEntry.publicKey, + hashAlgorithm: currentEntry.hashAlgorithm, + weight: currentEntry.weight, + isRevoked: true + ) + } + + /// Returns true if the given signatures are valid for the given signed data + access(all) + fun verify( + signatureSet: [KeyListSignature], + signedData: [UInt8], + domainSeparationTag: String + ): Bool { + + var validWeights: UFix64 = 0.0 + + let seenKeyIndices: {Int: Bool} = {} + + for signature in signatureSet { + + // Ensure the key index is valid + if signature.keyIndex >= self.entries.length { + return false + } + + // Ensure this key index has not already been seen + if seenKeyIndices[signature.keyIndex] ?? false { + return false + } + + // Record the key index was seen + seenKeyIndices[signature.keyIndex] = true + + // Get the actual key + let key = self.entries[signature.keyIndex] + + // Ensure the key is not revoked + if key.isRevoked { + return false + } + + // Ensure the signature is valid + if !key.publicKey.verify( + signature: signature.signature, + signedData: signedData, + domainSeparationTag: domainSeparationTag, + hashAlgorithm:key.hashAlgorithm + ) { + return false + } + + validWeights = validWeights + key.weight + } + + return validWeights >= 1.0 + } + } + + access(all) + struct KeyListSignature { + + access(all) + let keyIndex: Int + + access(all) + let signature: [UInt8] + + init(keyIndex: Int, signature: [UInt8]) { + self.keyIndex = keyIndex + self.signature = signature + } + } +}` + +type Transaction struct { + Name string + Body string + Setup string +} + +var testTransactions []Transaction + +func createTransaction(name string, imports string, prepare string, setup string) Transaction { + setupBody := "" + if setup != "" { + setupBody = fmt.Sprintf( + ` + transaction(){ + prepare(signer: auth(Storage, Contracts, Keys, Inbox, Capabilities) &Account) { + %s + } + }`, + setup, + ) + } + return Transaction{ + Name: name, + Body: fmt.Sprintf( + ` + // %s + %s + + transaction(){ + prepare(signer: auth(Storage, Contracts, Keys, Inbox, Capabilities) &Account) { + %s + } + }`, + name, + imports, + prepare, + ), + Setup: setupBody, + } +} + +func init() { + // placeholder hex-encoded zero value + placeholderHexValue := "0000000000000000000000000000000000000000000000000000000000000000" + + // verify signature transaction + numKeys := uint64(15) + message := []byte("hello world") + + rawKeys := make([]string, numKeys) + signatures := make([]string, numKeys) + + for i := 0; i < int(numKeys); i++ { + rawKeys[i] = placeholderHexValue + signatures[i] = placeholderHexValue + } + + verifySignatureTransaction := transactions.VerifySignatureTransaction(numKeys, message, rawKeys, signatures) + + // bls + numBLSKeys := 42 + pks := make([]string, numBLSKeys) + for i := 0; i < numBLSKeys; i++ { + pks[i] = placeholderHexValue + } + blsAggregateKeysTransaction := transactions.AggregateBLSAggregateKeysTransaction(numBLSKeys, pks) + blsVerifyProofOfPossessionTransaction := transactions.BLSVerifyProofOfPossessionTransaction(8, placeholderHexValue, placeholderHexValue) + + testTransactions = []Transaction{ + createTransaction( + "EmptyLoop", + "", + transactions.EmptyLoopTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "AssertTrue", + "", + transactions.AssertTrueTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "GetSignerAddress", + "", + transactions.GetSignerAddressTransaction(50).GetPrepareBlock(), + "", + ), + createTransaction( + "GetSignerPublicAccount", + "", + transactions.GetSignerPublicAccountTransaction(50).GetPrepareBlock(), + "", + ), + createTransaction( + "GetSignerAccountBalance", + "", + transactions.GetSignerAccountBalanceTransaction(30).GetPrepareBlock(), + "", + ), + createTransaction( + "GetSignerAccountAvailableBalance", + "", + transactions.GetSignerAccountAvailableBalanceTransaction(30).GetPrepareBlock(), + "", + ), + createTransaction( + "GetSignerAccountStorageUsed", + "", + transactions.GetSignerAccountStorageUsedTransaction(30).GetPrepareBlock(), + "", + ), + createTransaction( + "GetSignerAccountStorageCapacity", + "", + transactions.GetSignerAccountStorageCapacityTransaction(30).GetPrepareBlock(), + "", + ), + createTransaction( + "BorrowSignerAccountFlowTokenVault", + "import FungibleToken from 0x1\nimport FlowToken from 0x1", + transactions.BorrowSignerAccountFlowTokenVaultTransaction(30).GetPrepareBlock(), + "", + ), + createTransaction( + "BorrowSignerAccountFungibleTokenReceiver", + "import FungibleToken from 0x1\nimport FlowToken from 0x1", + transactions.BorrowSignerAccountFungibleTokenReceiverTransaction(30).GetPrepareBlock(), + "", + ), + createTransaction( + "TransferTokensToSelf", + "import FungibleToken from 0x1\nimport FlowToken from 0x1", + transactions.TransferTokensToSelfTransaction(30).GetPrepareBlock(), + "", + ), + createTransaction( + "CreateNewAccount", + "", + transactions.CreateNewAccountTransaction(10).GetPrepareBlock(), + "", + ), + createTransaction( + "CreateNewAccountWithContract", + "", + transactions.CreateNewAccountWithContractTransaction(10).GetPrepareBlock(), + "", + ), + createTransaction( + "DecodeHex", + "", + transactions.DecodeHexTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "RevertibleRandomNumber", + "", + transactions.RevertibleRandomTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "NumberToStringConversion", + "", + transactions.NumberToStringConversionTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "ConcatenateString", + "", + transactions.ConcatenateStringTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "BorrowString", + "", + transactions.BorrowStringTransaction.GetPrepareBlock(), + fmt.Sprintf( + transactions.BorrowStringTransaction.GetSetupTemplate(), + transactions.StringArrayOfLen(20, 100), + ), + ), + createTransaction( + "CopyString", + "", + transactions.CopyStringTransaction.GetPrepareBlock(), + fmt.Sprintf( + transactions.CopyStringTransaction.GetSetupTemplate(), + transactions.StringArrayOfLen(20, 100), + ), + ), + createTransaction( + "CopyStringAndSaveDuplicate", + "", + transactions.CopyStringAndSaveADuplicateTransaction.GetPrepareBlock(), + fmt.Sprintf( + transactions.CopyStringAndSaveADuplicateTransaction.GetSetupTemplate(), + transactions.StringArrayOfLen(20, 100), + ), + ), + createTransaction( + "StoreAndLoadDictString", + "", + transactions.StoreAndLoadDictStringTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "StoreLoadAndDestroyDictString", + "", + transactions.StoreLoadAndDestroyDictStringTransaction.GetPrepareBlock(), + fmt.Sprintf( + transactions.StoreLoadAndDestroyDictStringTransaction.GetSetupTemplate(), + transactions.StringDictOfLen(100, 100), + ), + ), + createTransaction( + "BorrowDictString", + "", + transactions.BorrowDictStringTransaction.GetPrepareBlock(), + fmt.Sprintf( + transactions.BorrowDictStringTransaction.GetSetupTemplate(), + transactions.StringDictOfLen(100, 100), + ), + ), + createTransaction( + "CopyDictString", + "", + transactions.CopyDictStringTransaction.GetPrepareBlock(), + fmt.Sprintf( + transactions.CopyDictStringTransaction.GetSetupTemplate(), + transactions.StringDictOfLen(30, 100), + ), + ), + createTransaction( + "CopyDictStringAndSaveDuplicate", + "", + transactions.CopyDictStringAndSaveADuplicateTransaction.GetPrepareBlock(), + fmt.Sprintf( + transactions.CopyDictStringAndSaveADuplicateTransaction.GetSetupTemplate(), + transactions.StringDictOfLen(20, 100), + ), + ), + createTransaction( + "LoadDictAndDestroy", + "", + transactions.LoadDictAndDestroyItTransaction.GetPrepareBlock(), + fmt.Sprintf( + transactions.LoadDictAndDestroyItTransaction.GetSetupTemplate(), + 100, + ), + ), + createTransaction( + "AddKeyToAccount", + "", + transactions.AddKeyToAccountTransaction(50).GetPrepareBlock(), + "", + ), + createTransaction( + "AddAndRevokeKeyToAccount", + "", + transactions.AddAndRevokeKeyToAccountTransaction(40).GetPrepareBlock(), + "", + ), + createTransaction( + "GetAccountKey", + "", + transactions.GetAccountKeyTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "GetContracts", + "", + transactions.GetContractsTransaction(100).GetPrepareBlock(), + transactions.GetContractsTransaction(100).GetSetupTemplate(), + ), + createTransaction( + "Hash", + "import Crypto from 0x1", + transactions.HashTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "StringToLower", + "", + transactions.StringToLowerTransaction(100, 100).GetPrepareBlock(), + "", + ), + createTransaction( + "GetCurrentBlock", + "", + transactions.GetCurrentBlockTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "GetBlockAt", + "", + transactions.GetBlockAtTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "DestroyResourceDictionary", + "", + transactions.DestroyResourceDictionaryTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "ParseUFix64", + "", + transactions.ParseUFix64Transaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "ParseFix64", + "", + transactions.ParseFix64Transaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "ParseUInt64", + "", + transactions.ParseUInt64Transaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "ParseInt64", + "", + transactions.ParseInt64Transaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "ParseInt", + "", + transactions.ParseIntTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "IssueStorageCapability", + "", + transactions.IssueStorageCapabilityTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "GetKeyCount", + "", + transactions.GetKeyCountTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "CreateKeyECDSAP256", + "", + transactions.CreateKeyECDSAP256Transaction(100, placeholderHexValue).GetPrepareBlock(), + "", + ), + createTransaction( + "CreateKeyECDSAsecp256k1", + "", + transactions.CreateKeyECDSAsecp256k1Transaction(100, placeholderHexValue).GetPrepareBlock(), + "", + ), + createTransaction( + "CreateKeyBLSBLS12381", + "", + transactions.CreateKeyBLSBLS12381Transaction(100, placeholderHexValue).GetPrepareBlock(), + "", + ), + createTransaction( + "ArrayInsert", + "", + transactions.ArrayInsertTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "ArrayInsertRemove", + "", + transactions.ArrayInsertRemoveTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "ArrayInsertSetRemove", + "", + transactions.ArrayInsertSetRemoveTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "ArrayInsertMap", + "", + transactions.ArrayInsertMapTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "ArrayInsertFilterRemove", + "", + transactions.ArrayInsertFilterTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "ArrayAppend", + "", + transactions.ArrayAppendTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "DictInsert", + "", + transactions.DictInsertTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "DictInsertRemove", + "", + transactions.DictInsertRemoveTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "DictInsertSetRemove", + "", + transactions.DictInsertSetRemoveTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "DictIterCopy", + "", + transactions.DictIterCopyTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "ArrayCreateBatch", + "", + transactions.ArrayCreateBatchTransaction(100).GetPrepareBlock(), + "", + ), + createTransaction( + "VerifySignatureTransaction", + "import Crypto from 0x1", + verifySignatureTransaction.GetPrepareBlock(), + "", + ), + createTransaction( + "AggregateBLSAggregateKeys", + "", + blsAggregateKeysTransaction.GetPrepareBlock(), + "", + ), + createTransaction( + "BLSVerifyProofOfPossession", + "", + blsVerifyProofOfPossessionTransaction.GetPrepareBlock(), + "", + ), + } +} + +func createRuntimeInterface(b *testing.B, signerAccount *common.Address, contractsAddress *common.Address) *TestRuntimeInterface { + accountCodes := map[common.Location][]byte{} + accountCounter := uint64(4) + created := false + *signerAccount = *contractsAddress + + return &TestRuntimeInterface{ + OnGetCode: func(location common.Location) (bytes []byte, err error) { + return accountCodes[location], nil + }, + Storage: NewTestLedger(nil, nil), + OnGetSigningAccounts: func() ([]common.Address, error) { + return []common.Address{*signerAccount}, nil + }, + OnResolveLocation: NewSingleIdentifierLocationResolver(b), + OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { + return accountCodes[location], nil + }, + OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { + accountCodes[location] = code + return nil + }, + OnEmitEvent: func(event cadence.Event) error { + return nil + }, + OnDecodeArgument: func(b []byte, t cadence.Type) (value cadence.Value, err error) { + return json.Decode(nil, b) + }, + OnGetAccountBalance: func(address common.Address) (uint64, error) { + return 0, nil + }, + OnGetAccountAvailableBalance: func(address common.Address) (uint64, error) { + return 0, nil + }, + OnGetStorageUsed: func(address common.Address) (uint64, error) { + return 0, nil + }, + OnGetStorageCapacity: func(address common.Address) (uint64, error) { + return 0, nil + }, + OnCreateAccount: func(payer Address) (address Address, err error) { + accountCounter++ + addressBytes := make([]byte, 8) + binary.BigEndian.PutUint64(addressBytes, accountCounter) + result := interpreter.NewUnmeteredAddressValueFromBytes(addressBytes) + return result.ToAddress(), nil + }, + OnValidatePublicKey: func(key *stdlib.PublicKey) error { + return nil + }, + OnVerifySignature: func( + signature []byte, + tag string, + signedData []byte, + publicKey []byte, + signatureAlgorithm SignatureAlgorithm, + hashAlgorithm HashAlgorithm, + ) (bool, error) { + return true, nil + }, + OnHash: func(data []byte, tag string, hashAlgorithm HashAlgorithm) ([]byte, error) { + return data, nil + }, + OnBLSVerifyPOP: func(pk *stdlib.PublicKey, s []byte) (bool, error) { + return true, nil + }, + OnBLSAggregateSignatures: func(sigs [][]byte) ([]byte, error) { + if len(sigs) == 0 { + return nil, fmt.Errorf("no signatures to aggregate") + } + return sigs[0], nil + }, + OnBLSAggregatePublicKeys: func(keys []*stdlib.PublicKey) (*stdlib.PublicKey, error) { + if len(keys) == 0 { + return nil, fmt.Errorf("no keys to aggregate") + } + return keys[0], nil + }, + OnAddAccountKey: func(address Address, publicKey *stdlib.PublicKey, hashAlgo HashAlgorithm, weight int) (*stdlib.AccountKey, error) { + return &stdlib.AccountKey{PublicKey: publicKey, HashAlgo: hashAlgo, Weight: weight}, nil + }, + OnGetAccountKey: func(address Address, index uint32) (*stdlib.AccountKey, error) { + return &stdlib.AccountKey{KeyIndex: index, PublicKey: &stdlib.PublicKey{}}, nil + }, + OnRemoveAccountKey: func(address Address, index uint32) (*stdlib.AccountKey, error) { + return &stdlib.AccountKey{KeyIndex: index, PublicKey: &stdlib.PublicKey{}}, nil + }, + OnAccountKeysCount: func(address Address) (uint32, error) { + return 1, nil + }, + OnGetAccountContractNames: func(address Address) ([]string, error) { + if created { + // ensures GetContractsTransaction only creates the contracts once + return []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", + "11", "12", "13", "14", "15", "16", "17", "18", "19", "20"}, nil + } + created = true + return []string{}, nil + }, + } +} + +func setupRuntime(b *testing.B, signerAccount *common.Address, contractsAddress *common.Address, senderAddress *common.Address, receiverAddress *common.Address, environment Environment, useVM bool) (TestRuntime, func() common.TransactionLocation, *TestRuntimeInterface) { + runtimeInterface := createRuntimeInterface(b, signerAccount, contractsAddress) + *signerAccount = *contractsAddress + + runtime := NewTestRuntime() + nextTransactionLocation := NewTransactionLocationGenerator() + + // Deploy Fungible Token contract + err := runtime.ExecuteTransaction( + Script{ + Source: DeploymentTransaction( + "FungibleToken", + []byte(modifiedFungibleTokenContractInterface), + ), + }, + Context{ + Interface: runtimeInterface, + Location: nextTransactionLocation(), + Environment: environment, + UseVM: useVM, + }, + ) + require.NoError(b, err) + + // Deploy Flow Token contract + err = runtime.ExecuteTransaction( + Script{ + Source: DeploymentTransaction("FlowToken", []byte(modifiedFlowContract)), + }, + Context{ + Interface: runtimeInterface, + Location: nextTransactionLocation(), + Environment: environment, + UseVM: useVM, + }, + ) + require.NoError(b, err) + + // Deploy Crypto contract + err = runtime.ExecuteTransaction( + Script{ + Source: DeploymentTransaction("Crypto", []byte(realCryptoContract)), + }, + Context{ + Interface: runtimeInterface, + Location: nextTransactionLocation(), + Environment: environment, + UseVM: useVM, + }, + ) + require.NoError(b, err) + + // Setup both user accounts for Flow Token + for _, address := range []common.Address{ + *senderAddress, + *receiverAddress, + } { + *signerAccount = address + + err = runtime.ExecuteTransaction( + Script{ + Source: []byte(realSetupFlowTokenAccountTransaction), + }, + Context{ + Interface: runtimeInterface, + Location: nextTransactionLocation(), + Environment: environment, + UseVM: useVM, + }, + ) + require.NoError(b, err) + } + + // Mint 1000 FLOW to sender + mintAmount, err := cadence.NewUFix64("100000000000.0") + require.NoError(b, err) + + *signerAccount = *contractsAddress + + err = runtime.ExecuteTransaction( + Script{ + Source: []byte(realMintFlowTokenTransaction), + Arguments: encodeArgs([]cadence.Value{ + cadence.Address(*senderAddress), + mintAmount, + }), + }, + Context{ + Interface: runtimeInterface, + Location: nextTransactionLocation(), + Environment: environment, + UseVM: useVM, + }, + ) + require.NoError(b, err) + + // Set signer account to sender for benchmark transactions + *signerAccount = *senderAddress + + return runtime, nextTransactionLocation, runtimeInterface +} + +func benchmarkRuntimeTransactions(b *testing.B, useVM bool) { + contractsAddress := common.MustBytesToAddress([]byte{0x1}) + senderAddress := common.MustBytesToAddress([]byte{0x2}) + receiverAddress := common.MustBytesToAddress([]byte{0x3}) + + var signerAccount common.Address + + var environment Environment + if useVM { + environment = NewBaseVMEnvironment(Config{}) + } else { + environment = NewBaseInterpreterEnvironment(Config{}) + } + + for _, transaction := range testTransactions { + + b.Run(transaction.Name, func(b *testing.B) { + // Create fresh runtime and storage for this sub-benchmark + runtime, nextTransactionLocation, runtimeInterface := setupRuntime( + b, + &signerAccount, + &contractsAddress, + &senderAddress, + &receiverAddress, + environment, + useVM, + ) + + for b.Loop() { + b.StopTimer() + // set up everything for the transaction + var err error + if transaction.Setup != "" { + err = runtime.ExecuteTransaction( + Script{ + Source: []byte(transaction.Setup), + Arguments: nil, + }, + Context{ + Interface: runtimeInterface, + Location: nextTransactionLocation(), + Environment: environment, + UseVM: useVM, + }, + ) + require.NoError(b, err) + } + source := []byte(transaction.Body) + location := nextTransactionLocation() + b.StartTimer() + + err = runtime.ExecuteTransaction( + Script{ + Source: source, + Arguments: nil, + }, + Context{ + Interface: runtimeInterface, + Location: location, + Environment: environment, + UseVM: useVM, + }, + ) + + b.StopTimer() + require.NoError(b, err) + b.StartTimer() + } + }) + } +} + +func BenchmarkRuntimeTransactionsInterpreter(b *testing.B) { + benchmarkRuntimeTransactions(b, false) +} + +func BenchmarkRuntimeTransactionsVM(b *testing.B) { + benchmarkRuntimeTransactions(b, true) +}