@@ -4,6 +4,7 @@ use crate::{
44 math_utils:: safe_div_usize,
55 stdlib:: {
66 any:: Any ,
7+ cell:: RefCell ,
78 collections:: { BTreeMap , HashMap , HashSet } ,
89 mem,
910 ops:: { Add , AddAssign , Mul , MulAssign , Sub , SubAssign } ,
@@ -55,6 +56,7 @@ use crate::{
5556use num_integer:: div_rem;
5657use num_traits:: { ToPrimitive , Zero } ;
5758use serde:: { Deserialize , Serialize } ;
59+ use starknet_crypto:: Signature ;
5860
5961use super :: { builtin_runner:: ModBuiltinRunner , cairo_pie:: CairoPieAdditionalData } ;
6062use super :: {
@@ -147,7 +149,13 @@ impl ResourceTracker for RunResources {
147149 }
148150}
149151
150- #[ derive( Clone ) ]
152+ /// Handles the creation of a CairoRunner
153+ ///
154+ /// This structure can be cloned. This allows to compute the initial state once,
155+ /// and execute it many times. The following elements can be cached:
156+ /// - Compiled hints
157+ /// - Decoded instructions
158+ /// - Loaded program segment
151159pub struct CairoRunnerBuilder {
152160 program : Program ,
153161 layout : CairoLayout ,
@@ -243,9 +251,6 @@ impl CairoRunnerBuilder {
243251 /// Note that *initializing* a builtin implies creating a runner for it,
244252 /// and *including* a builtin refers to enabling the builtin runner flag:
245253 /// `included`.
246- ///
247- /// TODO: Cloning the builder after calling this function leads to bad
248- /// behaviour (transactions revert). Why?
249254 pub fn initialize_builtin_runners_for_layout ( & mut self ) -> Result < ( ) , RunnerError > {
250255 let builtin_ordered_list = vec ! [
251256 BuiltinName :: output,
@@ -500,6 +505,47 @@ impl CairoRunnerBuilder {
500505 }
501506}
502507
508+ impl Clone for CairoRunnerBuilder {
509+ fn clone ( & self ) -> Self {
510+ let builtin_runners = self
511+ . builtin_runners
512+ . iter ( )
513+ . cloned ( )
514+ . map ( |mut builtin_runner| {
515+ // The SignatureBuiltinRunner contains an `Rc`, so deriving clone implies that
516+ // all runners built will share state. To workaround this, clone was implemented
517+ // manually.
518+ if let BuiltinRunner :: Signature ( signature) = & mut builtin_runner {
519+ let signatures = signature
520+ . signatures
521+ . as_ref ( )
522+ . borrow ( )
523+ . iter ( )
524+ . map ( |( k, v) | ( * k, Signature { r : v. r , s : v. s } ) )
525+ . collect ( ) ;
526+ signature. signatures = Rc :: new ( RefCell :: new ( signatures) )
527+ }
528+ builtin_runner
529+ } )
530+ . collect ( ) ;
531+ Self {
532+ program : self . program . clone ( ) ,
533+ layout : self . layout . clone ( ) ,
534+ runner_mode : self . runner_mode . clone ( ) ,
535+ enable_trace : self . enable_trace ,
536+ disable_trace_padding : self . disable_trace_padding ,
537+ allow_missing_builtins : self . allow_missing_builtins ,
538+ builtin_runners,
539+ program_base : self . program_base ,
540+ execution_base : self . execution_base ,
541+ memory : self . memory . clone ( ) ,
542+ loaded_program : self . loaded_program ,
543+ hints : self . hints . clone ( ) ,
544+ instructions : self . instructions . clone ( ) ,
545+ }
546+ }
547+ }
548+
503549pub struct CairoRunner {
504550 pub vm : VirtualMachine ,
505551 pub ( crate ) program : Program ,
0 commit comments