-
Notifications
You must be signed in to change notification settings - Fork 3
/
main.py
159 lines (136 loc) · 7.09 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
from vyper import compiler
from ethereum.tools import tester
from ethereum import utils as ethereum_utils
# http://web3py.readthedocs.io/en/stable
import web3
from web3 import Web3, HTTPProvider, EthereumTesterProvider, IPCProvider
from sys import platform
from web3.contract import Contract
GETH_IPC_PATH = '/Users/Ls/code/blockchain/geth-node/chaindata/geth.ipc'
GENERIC_PASSWORD_TO_ENCRYPT = 'test123456'
provider_ipc = IPCProvider(GETH_IPC_PATH);
# provider_ethereum_test = EthereumTesterProvider()
# HTTP Provider Reference: http://web3py.readthedocs.io/en/stable/providers.html#httpprovider
# Run `truffle develop` with a configuration to start Ganache CLI.
# It does not appear to work when I just run ganache-cli with flags such as `--port 9545`
provider_http = Web3.HTTPProvider("http://127.0.0.1:9545")
# web3.py instance
web3 = Web3(provider_http)
print('OS Platform: {}'.format(platform))
print('Web3 provider: {}'.format(web3))
# print("Block Number: %s", web3.eth.blockNumber)
def get_encoded_contract_constructor_arguments(constructor_args=None):
if constructor_args:
return contract_translator.encode_constructor_arguments(constructor_args['args'])
else:
return b''
def get_logs(last_receipt, contract, event_name=None):
# Get all log ids from the contract events
contract_log_ids = contract.translator.event_data.keys()
# Filter and return all logs originating from the contract
# or only those matching the event_name (if specified)
logs = [log for log in last_receipt.logs
if log.topics[0] in contract_log_ids and
log.address == contract.address and
(not event_name or
contract.translator.event_data[log.topics[0]]['name'] == event_name)]
assert len(logs) > 0, "No logs in the last receipt of the contract"
# Return all events decoded from the last receipt of the contract
return [contract.translator.decode_event(log.topics, log.data) for log in logs]
def get_last_log_from_contract_receipts(tester, contract, event_name=None):
# Get only the receipts for the last block from the chain (aka tester.s)
last_receipt = tester.s.head_state.receipts[-1]
# Get last log event with correct name and return the decoded event
print(get_logs(last_receipt, contract, event_name=event_name))
return get_logs(last_receipt, contract, event_name=event_name)[-1]
# Set the Vyper compiler to run when the Vyper language is requested
tester.languages['vyper'] = compiler.Compiler()
# Set the new "chain" (aka tester.s)
tester.s = tester.Chain()
tester.s.head_state.gas_limit = 10**9
initial_chain_state = tester.s.snapshot()
# Load contract source code
source_code = open('contracts/auctions/simple_open_auction.v.py').read()
# Compile contract code interface (aka tester.c)
FIVE_DAYS = 432000
tester.c = tester.s.contract(source_code, language='vyper', args=[tester.accounts[0], FIVE_DAYS])
# Generate ABI from contract source code
abi = tester.languages['vyper'].mk_full_signature(source_code)
print("ABI: %s", abi)
# Generate Contract Translator from ABI
contract_translator = tester.ContractTranslator(abi)
# Generate Bytecode from contract source code
contract_constructor_args = []
byte_code = tester.languages['vyper'].compile(source_code) + \
get_encoded_contract_constructor_arguments(contract_constructor_args)
# print("Bytecode: %s", byte_code)
address = tester.s.tx(to=b'', data=byte_code)
print("Address: %s", address)
# Instantiate contract from its ABI and Bytecode
contract_instance = tester.ABIContract(tester.s, abi, address)
print("Contract Instance: %s", contract_instance)
# Execute method on the tester chain to check the beneficiary is correct
assert ethereum_utils.remove_0x_head(tester.c.beneficiary()) == tester.accounts[0].hex()
# Execute method on the tester chain to check bidding time is 5 days
assert tester.c.auction_end() == tester.s.head_state.timestamp + FIVE_DAYS
# Revert chain state on failed transaction
tester.s.revert(initial_chain_state)
# Instantiate and deploy contract
contract_instance_web3 = web3.eth.contract(abi=abi, bytecode=byte_code)
print("Contract Instance with Web3: %s", contract_instance)
# Note: If we're running a Geth Node then I can use
# `web3.personal.listAccounts` but when I am using Ganache CLI
# I have to use `web3.eth.accounts` instead
if web3.personal.listAccounts:
# Geth Node
print("Accounts: %s", web3.personal.listAccounts[0])
first_account = web3.personal.listAccounts[0]
else:
# Ganache CLI on port 9545 with `truffle develop`
print("Accounts: %s", web3.eth.accounts[0])
first_account = web3.eth.accounts[0]
# Set Default account since this is used by
# /Users/Me/.pyenv/versions/3.6.2/lib/python3.6/site-packages/web3/contract.py", line 742
web3.eth.defaultAccount = first_account
print("Default Account: %s", web3.eth.defaultAccount);
if web3.personal.listAccounts:
# Only need to unlock the account when using Geth Node
# Note necessary when using Ganache CLI on port 9545 with `truffle develop`
print("Unlocked Default Account: %s", web3.personal.unlockAccount(web3.eth.defaultAccount, GENERIC_PASSWORD_TO_ENCRYPT))
# Alternative using Web3.py 4.1.0 and Geth
# https://github.com/ltfschoen/geth-node
# http://web3py.readthedocs.io/en/stable/contracts.html?highlight=deploy
# Get transaction hash from deployed contract
transaction_fields = {
'from': first_account,
'gasPrice': web3.eth.gasPrice
}
# Vyper contract Constructor Parameters expected
# i.e. See signature of Construction Function in simple_open_auction.v.py
# containing expected Constructor Parameters:
# def __init__(_beneficiary: address, _bidding_time: timedelta):
_bidding_time = 4000
contract_data = contract_instance_web3 \
.constructor(web3.eth.defaultAccount, _bidding_time) \
.buildTransaction(transaction_fields)
deploy_txn_hash = web3.eth.sendTransaction(contract_data)
print("Deployed Contract Tx Hash: %d", deploy_txn_hash)
# IMPORTANT: Ensure that you start mining in the Geth Node before
# the deploying the contract using the Geth JavaScript Console with `miner.start(1)`
# so it returns the tx receipt after its mined the block
mined_txn_receipt = web3.eth.waitForTransactionReceipt(deploy_txn_hash, timeout=1200)
print("Mined Transaction Receipt: %s", mined_txn_receipt)
txn_receipt = web3.eth.getTransactionReceipt(deploy_txn_hash)
print("Transaction Receipt: %s", txn_receipt)
# Note that the deployed Transaction Hash is shown in the Geth Logs.
# It may be used to obtain the tx receipt from the tx hash by running
# the following in the Geth JavaScript console:
# web3.eth.getTransactionReceipt('<INSERT_TRANSACTION_HASH')
deployed_contract_address = mined_txn_receipt['contractAddress']
contract_instance = web3.eth.contract(address=deployed_contract_address, abi=abi)
print("Contract Instance: %s", contract_instance)
print("Called Getter method beneficiary() from Deployed Contract Instance: %s",
contract_instance.functions.beneficiary().call())
print("Called Getter method auction_end() set by Constructor Parameter \
_bidding_time from Deployed Contract Instance: %s",
contract_instance.functions.auction_end().call())