@@ -320,6 +320,7 @@ export interface SimulationOutput {
320
320
executionResult: ExecutionResult ;
321
321
publicOutput: PublicSimulationOutput ;
322
322
privateOutput: NestedProcessReturnValues ;
323
+ error? : SimulationError ;
323
324
}
324
325
325
326
export interface UserAPI {
@@ -665,7 +666,7 @@ async simulate(userRequest: UserRequest): {
665
666
// If we're paying, e.g. in bananas, figure out how much AZT that is.
666
667
// Note: paymentMethod.getEquivalentAztBalance() may call `read` internally.
667
668
const equivalentAztBalance = await builder .paymentMethod .getEquivalentAztBalance ();
668
- gasEstimator = GasEstimator . fromAztBalance (equivalentAztBalance );
669
+ gasEstimator = new BinarySearchGasEstimator (equivalentAztBalance );
669
670
builder .setGasSettings (gasEstimator .proposeGasSettings ());
670
671
671
672
while (! gasEstimator .isConverged ()) {
@@ -889,6 +890,136 @@ const { request: deployAliceAccountRequest } = await aliceDappWrappedWallet.simu
889
890
```
890
891
891
892
893
+ ### Gas Estimation
894
+
895
+ ``` ts
896
+
897
+
898
+ export interface GasEstimator {
899
+ proposeGasSettings(): GasSettings ;
900
+ isConverged(): boolean ;
901
+ update(simulationOutput : SimulationOutput ): void ;
902
+ }
903
+
904
+ interface SearchRatios {
905
+ daToL2: number ;
906
+ daTearDown: number ;
907
+ l2TearDown: number ;
908
+ }
909
+
910
+ // Finds a balance that is enough to cover the gas costs of the simulation.
911
+ // Marks as converged if the simulation did not run out of gas,
912
+ // or if it is not possible to increase the balance further.
913
+ export class BinarySearchGasEstimator implements GasEstimator {
914
+ // keep the initial balance
915
+ // and the ratios of daGas to l2Gas
916
+ // as well as the ratios to teardownGas
917
+ private balance: number
918
+
919
+ // The upper and lower bounds of the search space.
920
+ // We start at the midpoint of these bounds.
921
+ // The search space is the balance, and the ratios of daGas to l2Gas
922
+ // as well as the ratios to teardownGas.
923
+ // The goal is to find a balance that is enough to cover the gas costs of the simulation.
924
+ // Then we can just use the true gas costs for the actual transaction.
925
+ private upperBounds: SearchRatios ;
926
+ private lowerBounds: SearchRatios ;
927
+ private current: SearchRatios ;
928
+ private mostRecentSimulation? : SimulationOutput ;
929
+ private iterations: number = 0 ;
930
+ private maxIterations: number = 10 ;
931
+ private epsilon: number = 0.01 ;
932
+
933
+
934
+
935
+ constructor (private balance : number ) {
936
+ this .lowerBounds = {
937
+ daToL2: 0 ,
938
+ daTearDown: 0 ,
939
+ l2TearDown: 0 ,
940
+ };
941
+ this .upperBounds = {
942
+ daToL2: 1 ,
943
+ daTearDown: 1 ,
944
+ l2TearDown: 1 ,
945
+ };
946
+ this .current = {
947
+ daToL2: .5 ,
948
+ daTearDown: .1 ,
949
+ l2TearDown: .1 ,
950
+ };
951
+ }
952
+
953
+ update(simulationOutput : SimulationOutput ): void {
954
+ // If the simulation ran out of DA gas
955
+ const oog = simulationOutput .getOutOfGas ();
956
+ if (! oog ) {
957
+ return
958
+ } else if (oog === ' da' ) {
959
+ // increase the balance
960
+ this .lowerBounds .daToL2 = this .current .daToL2 ;
961
+ } else if (oog === ' l2' ) {
962
+ // increase the balance
963
+ this .lowerBounds .daToL2 = this .current .daToL2 ;
964
+ } else if (oog === ' da_teardown' ) {
965
+ // increase the balance
966
+ this .lowerBounds .daTearDown = this .current .daTearDown ;
967
+ } else if (oog === ' l2_teardown' ) {
968
+ // increase the balance
969
+ this .lowerBounds .l2TearDown = this .current .l2TearDown ;
970
+ }
971
+ // update the current balance
972
+ this .current .daToL2 = (this .lowerBounds .daToL2 + this .upperBounds .daToL2 ) / 2 ;
973
+ this .current .daTearDown = (this .lowerBounds .daTearDown + this .upperBounds .daTearDown ) / 2 ;
974
+ this .current .l2TearDown = (this .lowerBounds .l2TearDown + this .upperBounds .l2TearDown ) / 2 ;
975
+ }
976
+
977
+ proposeGasSettings(): GasSettings {
978
+ return GasSettings .from ({
979
+ gasLimits: {
980
+ daGas: this .balance * this .current .daToL2 ,
981
+ l2Gas: this .balance * (1 - this .current .daToL2 ),
982
+ },
983
+ teardownGasLimits: {
984
+ daGas: this .balance * this .current .daToL2 * this .current .daTearDown ,
985
+ l2Gas: this .balance * (1 - this .current .daToL2 ) * this .current .l2TearDown ,
986
+ },
987
+ // This should actually be informed somehow
988
+ maxFeesPerGas: { daGas: 1 , l2Gas: 1 },
989
+ inclusionFee: 0
990
+ });
991
+ }
992
+
993
+ //
994
+ isConverged(): boolean {
995
+ // If the simulation did not run out of gas, we are converged.
996
+ if (! this .mostRecentSimulation ?.getOutOfGas ()) {
997
+ return true ;
998
+ }
999
+
1000
+ // If we have reached the maximum number of iterations, we are converged.
1001
+ if (this .iterations >= this .maxIterations ) {
1002
+ return true ;
1003
+ }
1004
+
1005
+ // If the search space is too small, we are converged.
1006
+ if (this .upperBounds .daToL2 - this .lowerBounds .daToL2 < this .epsilon ) {
1007
+ return true ;
1008
+ }
1009
+ if (this .upperBounds .daTearDown - this .lowerBounds .daTearDown < this .epsilon ) {
1010
+ return true ;
1011
+ }
1012
+ if (this .upperBounds .l2TearDown - this .lowerBounds .l2TearDown < this .epsilon ) {
1013
+ return true ;
1014
+ }
1015
+
1016
+ return false ;
1017
+
1018
+ }
1019
+
1020
+ }
1021
+
1022
+ ```
892
1023
893
1024
### Concerns
894
1025
0 commit comments