11
11
from abc import ABC , abstractmethod
12
12
import threading
13
13
import random
14
+ from copy import deepcopy
14
15
15
16
from sqlalchemy .orm import Session
16
17
from backend .consensus .vrf import get_validators_for_transaction
@@ -1034,6 +1035,12 @@ async def process_leader_appeal(
1034
1035
)
1035
1036
transaction .appeal_undetermined = True
1036
1037
1038
+ context .contract_snapshot_supplier = (
1039
+ lambda : context .contract_snapshot_factory (
1040
+ context .transaction .to_address
1041
+ )
1042
+ )
1043
+
1037
1044
# Begin state transitions starting from PendingState
1038
1045
state = PendingState ()
1039
1046
while True :
@@ -1597,16 +1604,21 @@ async def handle(self, context):
1597
1604
if context .transaction .leader_only :
1598
1605
context .remaining_validators = []
1599
1606
1600
- # Create a contract snapshot for the transaction
1601
- contract_snapshot_supplier = lambda : context .contract_snapshot_factory (
1602
- context .transaction .to_address
1603
- )
1607
+ # Create a contract snapshot for the transaction if not exists
1608
+ if context .transaction .contract_snapshot :
1609
+ contract_snapshot = deepcopy (context .transaction .contract_snapshot )
1610
+ else :
1611
+ contract_snapshot_supplier = lambda : context .contract_snapshot_factory (
1612
+ context .transaction .to_address
1613
+ )
1614
+ context .contract_snapshot_supplier = contract_snapshot_supplier
1615
+ contract_snapshot = contract_snapshot_supplier ()
1604
1616
1605
1617
# Create a leader node for executing the transaction
1606
1618
leader_node = context .node_factory (
1607
1619
leader ,
1608
1620
ExecutionMode .LEADER ,
1609
- contract_snapshot_supplier () ,
1621
+ contract_snapshot ,
1610
1622
None ,
1611
1623
context .msg_handler ,
1612
1624
context .contract_snapshot_factory ,
@@ -1626,7 +1638,6 @@ async def handle(self, context):
1626
1638
1627
1639
# Set the validators and other context attributes
1628
1640
context .num_validators = len (context .remaining_validators ) + 1
1629
- context .contract_snapshot_supplier = contract_snapshot_supplier
1630
1641
context .votes = votes
1631
1642
1632
1643
# Transition to the CommittingState
@@ -1991,9 +2002,10 @@ async def handle(self, context):
1991
2002
leaders_contract_snapshot = context .contract_snapshot_supplier ()
1992
2003
1993
2004
# Set the contract snapshot for the transaction for a future rollback
1994
- context .transactions_processor .set_transaction_contract_snapshot (
1995
- context .transaction .hash , leaders_contract_snapshot .to_dict ()
1996
- )
2005
+ if not context .transaction .contract_snapshot :
2006
+ context .transactions_processor .set_transaction_contract_snapshot (
2007
+ context .transaction .hash , leaders_contract_snapshot .to_dict ()
2008
+ )
1997
2009
1998
2010
# Do not deploy or update the contract if the execution failed
1999
2011
if leader_receipt .execution_result == ExecutionResultStatus .SUCCESS :
@@ -2093,6 +2105,12 @@ async def handle(self, context):
2093
2105
else :
2094
2106
consensus_round = "Undetermined"
2095
2107
2108
+ # Save the contract snapshot for potential future appeals
2109
+ if not context .transaction .contract_snapshot :
2110
+ context .transactions_processor .set_transaction_contract_snapshot (
2111
+ context .transaction .hash , context .contract_snapshot_supplier ().to_dict ()
2112
+ )
2113
+
2096
2114
# Set the transaction result with the current consensus data
2097
2115
context .transactions_processor .set_transaction_result (
2098
2116
context .transaction .hash ,
0 commit comments