Skip to content

Commit 2907d9b

Browse files
mpaya5kstroobantscristiam86
authored
feat(hardhat): send consensus tx to hardhat network (#755)
* feat: add hardhat node and web3 package - Add Hardhat node service with Docker configuration - Configure hardhat.config.js with local network settings - Add 20 test accounts with 10,000 ETH each - Add web3 Python package to backend requirements - Update .gitignore for Hardhat artifacts and cache * feat: add contract and try script * feat: setup contract compilation and artifact handling - Add contract compilation setup with hardhat - Configure project structure for smart contracts - Fix file path for GhostContract.json artifact - Add necessary dependencies for contract compilation - Setup directory structure for contracts and artifacts * feat: creating hardhat transactions in consensus mechanism - Moved web3 python package into backend requirements file - Added access to compiled hardhat contract in jsonrpc service - Added database migration file so that a transaction has the ghost contract address of hardhat network - When a genlayer contract is deployed then a hardhat contract is deployed, both are linked in the CurrentState table - When a genlayer write method is executed then the new transaction gets the hardhat contract from the CurrentState table - When a genlayer transaction changes from status then a rollup transaction is created on the hardhat network - todo: remove rollup transaction table, put hardhat port in env, link genlayer account to hardhat account, check for out of gas, remove prints * feat: put hardhat port in env * feat: remove rollup transactions database table * feat: free transactions on hardhat, one hardhat account * test: add hardhat test with code from the transaction_processor * fix: resolve pre-commit error * test: moved test to integration tests, upgrade web3 version in requirements as it gave an import error * feat(hardhat): add genlayer-consensus contracts and setup compilation - Add genlayer-consensus smart contracts to hardhat/contracts directory - Update hardhat.config.js to enable new code generator (viaIR: true) - Add @openzeppelin/contracts and @openzeppelin/contracts-upgradeable dependencies - Configure hardhat Docker container for contract compilation - Verify hardhat node functionality in genlayer-studio This commit sets up the smart contract development environment with the necessary dependencies and configurations to compile and deploy genlayer-consensus contracts. * feat: deleted amm_adaptive.py - Deleted amm_adaptive.py because is not using the new syntax I will upload the new amm_adaptive.py whenevir will be ready * fix: contract interaction - Fixed contract deployment state updates for frontend synchronization - Improved contract method interactions and state management - Ensured proper state updates after contract value changes * fix: pre-commit errors solved * fix: solved black pre-commit issue * feat(hardhat): add deployment persistence to hardhat node - Add volume mappings for deployments, artifacts and cache - Implement manual deployment file saving - Update hardhat configuration for proper deployment paths This change ensures that deployed contracts persist between container restarts by saving deployment data to mounted volumes. Note: Block persistence still requires a different solution (Ganache/Geth/Besu) as Hardhat Network doesn't support state persistence. Related issue: #669 * refactor(hardhat): integrate start script into Dockerfile - Removed start.sh script - Incorporated start script directly into Dockerfile for streamlined execution * fix(db): remove duplicate ghost_contract_address assignment Removes redundant assignment of ghost_contract_address in transaction_from_dict function to improve code clarity and prevent potential inconsistencies * fix(security): address SonarCloud warnings and improve test coverage - Ensure non-root user is used in Dockerfile to enhance security - Adjust permissions to avoid overly permissive access (777) on /app directories - Add tests to cover deployment scripts, ensuring proper functionality and coverage * commit: Add contract initialization and consensus service integration - Updated deploy_contracts.js to handle contract initialization after deployment - Added initial ConsensusService integration into server.py - Enhanced Dockerfile.hardhat with proper permissions and chainId handling - Started implementation of consensus_service.py with basic contract interactions Note: consensus_service.py still needs additional work for complete contract initialization and interaction methods. * feat(deploy): integrate contract deployment and backend service Integrate complete contract deployment persistence in Hardhat and create ConsensusService for contract interaction. - Add deployFixture to Hardhat deployment script to handle contract initialization - Create ConsensusService class to interact with deployed contracts from backend - Add deploy_fixture method to ConsensusService as fallback initialization option - Ensure consistent contract initialization between Hardhat and backend - Load contract artifacts and addresses in ConsensusService from deployment files The deployFixture now handles all contract initialization during deployment, while ConsensusService provides a Python interface to interact with the deployed contracts. The deploy_fixture method in ConsensusService mirrors the Hardhat initialization logic but is kept as a fallback option. * feat(hardhat): implement contract deployment flow and deployment backup system - Add consensus contract deployment flow with proper initialization sequence - Implement contract backup system for deployment persistence - Add deployment verification to prevent unnecessary redeployments - Create copy-deployments script for managing contract backups - Configure hardhat to handle contract compilation and deployment * feat(hardhat): implement contract deployment flow and deployment backup system - Add consensus contract deployment flow with proper initialization sequence - Implement contract backup system for deployment persistence - Add deployment verification to prevent unnecessary redeployments - Create copy-deployments script for managing contract backups - Configure hardhat to handle contract compilation and deployment * refactor: remove ghost_contract_address redundant references - Remove ghost_contract_address from transactions_processor to avoid duplication - Remove unused ghost_contract_address from types.py * refactor: replace hardhat-deploy with hardhat-ignition - Migrate deployment process from hardhat-deploy to hardhat-ignition - Create DeployFixture module following TransactionFlow deployment order - Update deployment tests to ensure initialization and contract connecton as TransactionFlow * refactor: remove deployFixture from consensus_service.py - Remove unused deployFixture function from consensus_service.py - Deployment now handled entirely through hardhat-ignition * feat(rpc): add eth_getContract endpoint to retrieve deployed contract addresses - Add new RPC endpoint to fetch contract information by name - Return contract address for deployed contracts - Register endpoint in RPC server initialization * refactor(consensus): remove unused methods from ConsensusService - Remove _send_transaction helper method as it's not being used - Remove get_accounts method as it's no longer needes * feat(rpc): enhance eth_getContract endpoint with ABI and message handling - Add ABI to contract endpoint response for better contract interaction - Integrate MessageHandler into ConsensusService for improved logging * feat(hardhat): add bytecode to contract deployment data - Include bytecode in saved deployment JSON files - Included bytecode in the response for the eth_getContract endpoint * refactor: delete msg_handler in ConsensusService * refactor: delete msg_handler in ConsensusService * refactor: delete msg_handler in ConsensusService * feat: enable transaction submission to node in transactions_processor - Uncomment transaction submission code in transactions_processor - Add consensus_service to fetch GhostContract ABI and bytecode * feat(consensus): Integrate create_rollup_transactions in consensus execution - Added code to call the create_rollup_transactions method from the TransactionsProcessor. - This integration allows for sending transactions to the Hardhat node during consensus executins. * fix: used pre-commit * fix: encapsule send_raw_transactions into a try-except block * feat: improved how JSON responses are shown in the Studio UI * fix: get deployed smart contracts latest abi * feat: decode transactions pointing to consensus smart contracts * fix: remove unused code * chore: updated genlayerjs * feat: forward transactions to the hardhat network * fix: catch exception when posting transactions to the rollup layer * fix: transaction ype and genlayer tx data decoding * test: fixed transaction encoding for tests * fix: transaction parser unit tests * chore: updated genlayer-js to latest version --------- Co-authored-by: kstroobants <stroobants.kristof@hotmail.com> Co-authored-by: Cristiam Da Silva <cristiam86@gmail.com>
1 parent f86ed86 commit 2907d9b

27 files changed

+1258
-733
lines changed

.env.example

+5
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ HARDHAT_URL = 'http://hardhat'
6161
HARDHAT_PORT = '8545'
6262
HARDHAT_PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'
6363

64+
# Consensus Parameters
65+
CONSENSUS_CONTRACT_ADDRESS = '0x0000000000000000000000000000000000000000'
66+
DEFAULT_NUM_INITIAL_VALIDATORS = 5
67+
DEFAULT_CONSENSUS_MAX_ROTATIONS = 3
68+
6469
# LLM Providers Configuration
6570
# If you want to use OpenAI LLMs, add your key here
6671
OPENAIKEY = '<add_your_openai_api_key_here>'

backend/consensus/base.py

+33
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,8 @@ def execute_transfer(
324324
TransactionStatus.UNDETERMINED,
325325
msg_handler,
326326
)
327+
328+
transactions_processor.create_rollup_transaction(transaction.hash)
327329
return
328330

329331
# Update the balance of the sender account
@@ -349,6 +351,8 @@ def execute_transfer(
349351
msg_handler,
350352
)
351353

354+
transactions_processor.create_rollup_transaction(transaction.hash)
355+
352356
def run_appeal_window_loop(self):
353357
"""
354358
Run the loop to handle the appeal window.
@@ -784,6 +788,10 @@ async def handle(self, context):
784788
context.msg_handler,
785789
)
786790

791+
context.transactions_processor.create_rollup_transaction(
792+
context.transaction.hash
793+
)
794+
787795
# Unpack the leader and validators
788796
[leader, *remaining_validators] = validators
789797

@@ -851,6 +859,10 @@ async def handle(self, context):
851859
context.msg_handler,
852860
)
853861

862+
context.transactions_processor.create_rollup_transaction(
863+
context.transaction.hash
864+
)
865+
854866
# Create validator nodes for each validator
855867
context.validator_nodes = [
856868
context.node_factory(
@@ -898,6 +910,10 @@ async def handle(self, context):
898910
context.msg_handler,
899911
)
900912

913+
context.transactions_processor.create_rollup_transaction(
914+
context.transaction.hash
915+
)
916+
901917
# Process each validation result and update the context
902918
for i, validation_result in enumerate(context.validation_results):
903919
# Store the vote from each validator node
@@ -977,6 +993,11 @@ async def handle(self, context):
977993
TransactionStatus.PENDING,
978994
context.msg_handler,
979995
)
996+
997+
context.transactions_processor.create_rollup_transaction(
998+
context.transaction.hash
999+
)
1000+
9801001
context.transactions_processor.set_transaction_appeal_failed(
9811002
context.transaction.hash,
9821003
0,
@@ -1036,6 +1057,10 @@ async def handle(self, context):
10361057
context.msg_handler,
10371058
)
10381059

1060+
context.transactions_processor.create_rollup_transaction(
1061+
context.transaction.hash
1062+
)
1063+
10391064
# Set the transaction result
10401065
context.transactions_processor.set_transaction_result(
10411066
context.transaction.hash, context.consensus_data.to_dict()
@@ -1130,6 +1155,10 @@ async def handle(self, context):
11301155
context.msg_handler,
11311156
)
11321157

1158+
context.transactions_processor.create_rollup_transaction(
1159+
context.transaction.hash
1160+
)
1161+
11331162
# Set the transaction result with the current consensus data
11341163
context.transactions_processor.set_transaction_result(
11351164
context.transaction.hash,
@@ -1161,6 +1190,10 @@ async def handle(self, context):
11611190
context.msg_handler,
11621191
)
11631192

1193+
context.transactions_processor.create_rollup_transaction(
1194+
context.transaction.hash
1195+
)
1196+
11641197
# Insert pending transactions generated by contract-to-contract calls
11651198
pending_transactions = (
11661199
context.transaction.consensus_data.leader_receipt.pending_transactions

backend/database_handler/transactions_processor.py

+36-91
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
from backend.database_handler.contract_snapshot import ContractSnapshot
1717
import os
1818

19+
from backend.rollup.consensus_service import ConsensusService
20+
1921

2022
class TransactionAddressFilter(Enum):
2123
ALL = "all"
@@ -145,64 +147,6 @@ def insert_transaction(
145147
)
146148
ghost_contract_address = None
147149

148-
if type == TransactionType.DEPLOY_CONTRACT.value:
149-
# Hardhat account
150-
account = self.web3.eth.accounts[0]
151-
private_key = os.environ.get("HARDHAT_PRIVATE_KEY")
152-
153-
# Ghost contract
154-
# Read contract ABI and bytecode from compiled contract
155-
# contract_file = os.path.join(
156-
# os.getcwd(),
157-
# "app/hardhat/artifacts/contracts/GhostContract.sol/GhostContract.json",
158-
# )
159-
160-
# with open(contract_file, "r") as f:
161-
# contract_json = json.loads(f.read())
162-
# abi = contract_json["abi"]
163-
# bytecode = contract_json["bytecode"]
164-
165-
# # Create the contract instance
166-
# contract = self.web3.eth.contract(abi=abi, bytecode=bytecode)
167-
168-
# # Build the transaction
169-
# gas_estimate = self.web3.eth.estimate_gas(
170-
# contract.constructor().build_transaction(
171-
# {
172-
# "from": account,
173-
# "nonce": self.web3.eth.get_transaction_count(account),
174-
# "gasPrice": 0,
175-
# }
176-
# )
177-
# )
178-
# transaction = contract.constructor().build_transaction(
179-
# {
180-
# "from": account,
181-
# "nonce": self.web3.eth.get_transaction_count(account),
182-
# "gas": gas_estimate,
183-
# "gasPrice": 0,
184-
# }
185-
# )
186-
187-
# # Sign the transaction
188-
# signed_tx = self.web3.eth.account.sign_transaction(
189-
# transaction, private_key=private_key
190-
# )
191-
192-
# # Send the transaction
193-
# tx_hash = self.web3.eth.send_raw_transaction(signed_tx.raw_transaction)
194-
195-
# # Wait for the transaction receipt
196-
# receipt = self.web3.eth.wait_for_transaction_receipt(tx_hash)
197-
# ghost_contract_address = receipt.contractAddress
198-
199-
elif type == TransactionType.RUN_CONTRACT.value:
200-
genlayer_contract_address = to_address
201-
# contract_snapshot = ContractSnapshot(
202-
# genlayer_contract_address, self.session
203-
# )
204-
# ghost_contract_address = contract_snapshot.ghost_contract_address
205-
206150
new_transaction = Transactions(
207151
hash=transaction_hash,
208152
from_address=from_address,
@@ -235,9 +179,6 @@ def insert_transaction(
235179

236180
self.session.flush() # So that `created_at` gets set
237181

238-
if type != TransactionType.SEND.value:
239-
self.create_rollup_transaction(new_transaction.hash)
240-
241182
return new_transaction.hash
242183

243184
def get_transaction_by_hash(self, transaction_hash: str) -> dict | None:
@@ -280,36 +221,40 @@ def create_rollup_transaction(self, transaction_hash: str):
280221
account = self.web3.eth.accounts[0]
281222
private_key = os.environ.get("HARDHAT_PRIVATE_KEY")
282223

283-
# gas_estimate = self.web3.eth.estimate_gas(
284-
# {
285-
# "from": account,
286-
# "to": transaction.ghost_contract_address,
287-
# "value": transaction.value,
288-
# "data": rollup_input_data,
289-
# }
290-
# )
291-
292-
# transaction = {
293-
# "from": account,
294-
# "to": transaction.ghost_contract_address,
295-
# "value": transaction.value,
296-
# "data": rollup_input_data,
297-
# "nonce": self.web3.eth.get_transaction_count(account),
298-
# "gas": gas_estimate,
299-
# "gasPrice": 0,
300-
# }
301-
302-
# # Sign and send the transaction
303-
# signed_tx = self.web3.eth.account.sign_transaction(
304-
# transaction, private_key=private_key
305-
# )
306-
# tx_hash = self.web3.eth.send_raw_transaction(signed_tx.raw_transaction)
307-
308-
# # Wait for transaction to be actually mined and get the receipt
309-
# receipt = self.web3.eth.wait_for_transaction_receipt(tx_hash)
310-
311-
# # Get full transaction details including input data
312-
# transaction = self.web3.eth.get_transaction(tx_hash)
224+
try:
225+
gas_estimate = self.web3.eth.estimate_gas(
226+
{
227+
"from": account,
228+
"to": transaction.ghost_contract_address,
229+
"value": transaction.value,
230+
"data": rollup_input_data,
231+
}
232+
)
233+
234+
transaction = {
235+
"from": account,
236+
"to": transaction.ghost_contract_address,
237+
"value": transaction.value,
238+
"data": rollup_input_data,
239+
"nonce": self.web3.eth.get_transaction_count(account),
240+
"gas": gas_estimate,
241+
"gasPrice": 0,
242+
}
243+
244+
# Sign and send the transaction
245+
signed_tx = self.web3.eth.account.sign_transaction(
246+
transaction, private_key=private_key
247+
)
248+
tx_hash = self.web3.eth.send_raw_transaction(signed_tx.raw_transaction)
249+
250+
# Wait for transaction to be actually mined and get the receipt
251+
receipt = self.web3.eth.wait_for_transaction_receipt(tx_hash)
252+
253+
# Get full transaction details including input data
254+
transaction = self.web3.eth.get_transaction(tx_hash)
255+
256+
except Exception as e:
257+
print(f"Error creating rollup transaction: {e}")
313258

314259
def get_transaction_count(self, address: str) -> int:
315260
count = (

0 commit comments

Comments
 (0)