Skip to content

Commit 565ddae

Browse files
authored
Merge pull request #9 from lsd-ucsc/dev
Build against latest solc and ganache
2 parents e787a2c + 3f876ea commit 565ddae

File tree

7 files changed

+243
-6
lines changed

7 files changed

+243
-6
lines changed

.github/workflows/create-release.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ jobs:
1717
python-version: [ 3.11 ]
1818
node-version: [ 18.16.0 ]
1919

20-
ganache-version: [ 7.8.0 ]
20+
ganache-version: [ 7.9.1 ]
2121

22-
solc-version: [ v0.8.20 ]
22+
solc-version: [ v0.8.21 ]
2323

2424
env:
2525
SOLC_BIN: ${{ github.workspace }}/build/solc-static-linux

.github/workflows/pubsub-solidity-unittesting.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
strategy:
2121
matrix:
2222
os: [ ubuntu-22.04 ]
23-
solc-version: [ 0.8.20 ]
23+
solc-version: [ 0.8.21 ]
2424
chain-fork: [ shanghai ]
2525
opt-runs: [ 200 ]
2626

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
MODULES := \
22
PubSub \
33
tests
4-
SOLC_VERSION := v0.8.20
4+
SOLC_VERSION := v0.8.21
55
MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
66
CURRENT_DIR := $(dir $(MKFILE_PATH))
77
SOLC_BIN := $(CURRENT_DIR)/build/solc-static-linux

tests/BasicActionGasCost.sol

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity >=0.4.17 <0.9.0;
3+
4+
5+
contract GasEvalSubscriber {
6+
constructor() {
7+
}
8+
9+
function onNotify(bytes memory data) external {
10+
// do nothing
11+
}
12+
}
13+
14+
15+
contract BasicActionGasCost {
16+
17+
event LogGasCost(uint8 idx, uint256 gasUsed);
18+
19+
address m_subAddr = address(0);
20+
bool m_someBool = false;
21+
mapping(address => bool) m_someMap;
22+
address m_someAddr = 0x0000000000000000000000000000000000000000;
23+
24+
constructor() {
25+
GasEvalSubscriber sub = new GasEvalSubscriber();
26+
m_subAddr = address(sub);
27+
28+
m_someMap[m_someAddr] = true;
29+
}
30+
31+
function eval() external {
32+
bytes memory data = new bytes(0);
33+
34+
uint256 gasStart = 0;
35+
uint256 gasUsed = 0;
36+
bool someBool = !m_someBool;
37+
address someAddr = msg.sender;
38+
address someAddr2 = m_someAddr;
39+
40+
gasStart = gasleft();
41+
GasEvalSubscriber(m_subAddr).onNotify(data);
42+
gasUsed = gasStart - gasleft();
43+
emit LogGasCost(1, gasUsed);
44+
45+
gasStart = gasleft();
46+
m_someBool = someBool;
47+
gasUsed = gasStart - gasleft();
48+
emit LogGasCost(2, gasUsed);
49+
50+
gasStart = gasleft();
51+
m_someMap[someAddr] = someBool;
52+
gasUsed = gasStart - gasleft();
53+
emit LogGasCost(3, gasUsed);
54+
55+
gasStart = gasleft();
56+
delete m_someMap[someAddr2];
57+
gasUsed = gasStart - gasleft();
58+
emit LogGasCost(4, gasUsed);
59+
60+
m_someBool = false;
61+
m_someMap[someAddr2] = true;
62+
}
63+
}

tests/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
MODULE_NAME := tests
22
CONTRACTS := \
33
HelloWorldPublisher \
4-
HelloWorldSubscriber
4+
HelloWorldSubscriber \
5+
BasicActionGasCost
56

67
MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
78
CURRENT_DIR := $(dir $(MKFILE_PATH))

utils/GanacheBasicActionTest.py

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
#!/usr/bin/env python3
2+
# -*- coding:utf-8 -*-
3+
###
4+
# Copyright (c) 2023 Roy Shadmon, Haofan Zheng
5+
# Use of this source code is governed by an MIT-style
6+
# license that can be found in the LICENSE file or at
7+
# https://opensource.org/licenses/MIT.
8+
###
9+
10+
11+
import logging
12+
import os
13+
import signal
14+
import subprocess
15+
import sys
16+
import time
17+
18+
from typing import List
19+
from web3 import Web3
20+
21+
22+
BASE_DIR_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
23+
BUILD_DIR_PATH = os.path.join(BASE_DIR_PATH, 'build')
24+
UTILS_DIR_PATH = os.path.join(BASE_DIR_PATH, 'utils')
25+
PYHELPER_DIR = os.path.join(UTILS_DIR_PATH, 'PyEthHelper')
26+
PROJECT_CONFIG_PATH = os.path.join(UTILS_DIR_PATH, 'project_conf.json')
27+
CHECKSUM_KEYS_PATH = os.path.join(BUILD_DIR_PATH, 'ganache_keys_checksum.json')
28+
GANACHE_KEYS_PATH = os.path.join(BUILD_DIR_PATH, 'ganache_keys.json')
29+
GANACHE_PORT = 7545
30+
NUM_OF_ACCOUNTS = 100
31+
GANACHE_NET_ID = 1337
32+
33+
34+
sys.path.append(PYHELPER_DIR)
35+
from PyEthHelper import EthContractHelper
36+
from PyEthHelper import GanacheAccounts
37+
38+
39+
def StartGanache() -> subprocess.Popen:
40+
cmd = [
41+
'ganache-cli',
42+
'-p', str(GANACHE_PORT),
43+
'-d',
44+
'-a', str(NUM_OF_ACCOUNTS),
45+
'--network-id', str(GANACHE_NET_ID),
46+
'--chain.hardfork', 'shanghai',
47+
'--wallet.accountKeysPath', str(GANACHE_KEYS_PATH),
48+
]
49+
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
50+
51+
return proc
52+
53+
54+
def ReadEvalLogEvents(logs: List[dict]) -> None:
55+
for log in logs:
56+
if (
57+
(len(log['topics']) > 0) and
58+
(
59+
log['topics'][0].hex() ==
60+
'0xe1ae46340cc3bb84afacee6678b86b538a6d5e4ce754adb3bfa9ce4e41d196ba'
61+
)
62+
):
63+
hexData = log['data'].hex()
64+
assert len(hexData) == 2 + (2 * (32 + 32)), 'Invalid log data length'
65+
bData = bytes.fromhex(hexData[2:])
66+
idx = int.from_bytes(bData[:32], byteorder='big')
67+
gasUsed = int.from_bytes(bData[32:], byteorder='big')
68+
print(f'Evaluated action at index {idx} with gas used {gasUsed}')
69+
70+
71+
def RunTests() -> dict:
72+
# connect to ganache
73+
ganacheUrl = 'http://localhost:{}'.format(GANACHE_PORT)
74+
w3 = Web3(Web3.HTTPProvider(ganacheUrl))
75+
while not w3.is_connected():
76+
print('Attempting to connect to ganache...')
77+
time.sleep(1)
78+
print('Connected to ganache')
79+
80+
# checksum keys
81+
GanacheAccounts.ChecksumGanacheKeysFile(
82+
CHECKSUM_KEYS_PATH,
83+
GANACHE_KEYS_PATH
84+
)
85+
86+
# setup account
87+
privKey = EthContractHelper.SetupSendingAccount(
88+
w3=w3,
89+
account=0,
90+
keyJson=CHECKSUM_KEYS_PATH
91+
)
92+
93+
# deploy BasicActionGasCost contract
94+
print('Deploying BasicActionGasCost contract...')
95+
baContract = EthContractHelper.LoadContract(
96+
w3=w3,
97+
projConf=PROJECT_CONFIG_PATH,
98+
contractName='BasicActionGasCost',
99+
release=None, # use locally built contract
100+
address=None, # deploy new contract
101+
)
102+
baReceipt = EthContractHelper.DeployContract(
103+
w3=w3,
104+
contract=baContract,
105+
arguments=[ ],
106+
privKey=privKey,
107+
gas=None, # let web3 estimate
108+
value=0,
109+
confirmPrompt=False # don't prompt for confirmation
110+
)
111+
baAddr = baReceipt.contractAddress
112+
print('BasicActionGasCost contract deployed at {}'.format(baAddr))
113+
114+
# load deployed BasicActionGasCost contract
115+
baContract = EthContractHelper.LoadContract(
116+
w3=w3,
117+
projConf=PROJECT_CONFIG_PATH,
118+
contractName='BasicActionGasCost',
119+
release=None, # use locally built contract
120+
address=baAddr, # use deployed contract
121+
)
122+
123+
evalTxReceipt = EthContractHelper.CallContractFunc(
124+
w3=w3,
125+
contract=baContract,
126+
funcName='eval',
127+
arguments=[ ],
128+
privKey=privKey,
129+
gas=None, # let web3 estimate
130+
value=0,
131+
confirmPrompt=False # don't prompt for confirmation
132+
)
133+
ReadEvalLogEvents(evalTxReceipt.logs)
134+
135+
136+
def StopGanache(ganacheProc: subprocess.Popen) -> None:
137+
print('Shutting down ganache (it may take ~15 seconds)...')
138+
waitEnd = time.time() + 20
139+
ganacheProc.terminate()
140+
while ganacheProc.poll() is None:
141+
try:
142+
if time.time() > waitEnd:
143+
print('Force to shut down ganache')
144+
ganacheProc.kill()
145+
else:
146+
print('Still waiting for ganache to shut down...')
147+
ganacheProc.send_signal(signal.SIGINT)
148+
ganacheProc.wait(timeout=2)
149+
except subprocess.TimeoutExpired:
150+
continue
151+
print('Ganache has been shut down')
152+
153+
154+
def main():
155+
logging.basicConfig(
156+
level=logging.DEBUG,
157+
format='%(asctime)s %(levelname)s %(name)s %(message)s'
158+
)
159+
160+
ganacheProc = StartGanache()
161+
162+
try:
163+
RunTests()
164+
165+
finally:
166+
# finish and exit
167+
StopGanache(ganacheProc)
168+
169+
170+
if __name__ == "__main__":
171+
main()
172+

utils/project_conf.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
"PubSubService" : "PubSub",
44
"EventManager" : "PubSub",
55
"HelloWorldPublisher" : "tests",
6-
"HelloWorldSubscriber": "tests"
6+
"HelloWorldSubscriber": "tests",
7+
"BasicActionGasCost" : "tests"
78
},
89
"releaseUrl": "https://github.com/lsd-ucsc/decent-pubsub-onchain/releases/download/{version}/{contract}",
910
"buildDir" : "build"

0 commit comments

Comments
 (0)