编译合约
Solidity编译合约的方式有很多选择,可以通过网上Remix在线编译,也可以下载编译器本地编译。这里为了方便,选择使用本地编译。通过Web3.py官方文档,可以pip install py-solc-x
包来编译,不过由于其在windows上安装依赖过于麻烦(还要装VS2019),所以还是选择用python调用node js的solcjs
工具进行编译,相关代码如下。
# 编译合约
def __init__(self,file):
os.system("solcjs "+file+" --bin --abi --optimize")
for fi in os.listdir():
if fi[-3:]=='abi':
os.rename(fi,'tmp.abi')
elif fi[-3:]=='bin':
os.rename(fi,'tmp.bin')
with open('tmp.bin','r') as f:
self.contractBin = "0x"+(f.readlines())[0]
with open('tmp.abi','r') as f:
self.contractAbi = json.loads((f.readlines())[0])
os.remove('tmp.abi')
os.remove('tmp.bin')
print('[!] 合约编译成功...')
部署合约
合约部署代码如下,注意在部署合约之前先对部署合约的账户进行解锁,并开启挖矿…
命令: personal.unlockAccount(eth.accounts[0])
# 部署合约
def deploy(self):
self.web3 = Web3(HTTPProvider('http://localhost:60000'))
if not self.web3.isConnected():
exit("[!] 请检查是否开启RPC服务...")
eth = self.web3.eth
# 添加默认账户,该账户需要提前解锁
eth.default_account = eth.accounts[0]
gasValue = eth.estimateGas({'data':self.contractBin})
print("[!] 合约部署预计消耗gas: "+str(gasValue))
tx_hash = eth.contract(
abi=self.contractAbi,
bytecode=self.contractBin).constructor().transact()
# 等待矿工打包区块
receipt=eth.waitForTransactionReceipt(tx_hash)
address = receipt['contractAddress']
print("[!] 合约部署成功,地址: "+str(address))
print("[!] 交易详情:"+str((receipt['transactionHash']).hex()))
self.address = address
调用合约
# 模拟攻击场景
def attack(self):
store_var_contract = self.web3.eth.contract(address=self.address, abi=self.contractAbi)
gas_estimate = store_var_contract.functions.sub_underflow().estimateGas()
print('[!] 调用合约函数 sub_underflow() 消耗gas:'+str(gas_estimate))
print('[!] 合约返回: '+str(store_var_contract.functions.sub_underflow().call()))
#receipt = self.web3.eth.waitForTransactionReceipt(tx_hash)
#print(receipt)
#print("[!] 合约调用成功, 交易详情:"+str((receipt['transactionHash']).hex()))
#print(receipt["status"])
小结
这里通过使用python-web3.py 对合约进行部署和调用,是因为我想通过geth批量的执行命令,所以打算用python调用合约来模拟攻击过程。最好其实应该使用Node.js进行脚本编写,无奈对js不太熟悉,所以选择python。总的代码及运行结果如下:
import os,json,sys
from web3 import Web3,HTTPProvider
class contract:
# 编译合约
def __init__(self,file):
os.system("solcjs "+file+" --bin --abi --optimize")
for fi in os.listdir():
if fi[-3:]=='abi':
os.rename(fi,'tmp.abi')
elif fi[-3:]=='bin':
os.rename(fi,'tmp.bin')
with open('tmp.bin','r') as f:
self.contractBin = "0x"+(f.readlines())[0]
with open('tmp.abi','r') as f:
self.contractAbi = json.loads((f.readlines())[0])
os.remove('tmp.abi')
os.remove('tmp.bin')
print('[!] 合约编译成功...')
# 部署合约
def deploy(self):
self.web3 = Web3(HTTPProvider('http://localhost:60000'))
if not self.web3.isConnected():
exit("[!] 请检查是否开启RPC服务...")
eth = self.web3.eth
eth.default_account = eth.accounts[0]
gasValue = eth.estimateGas({'data':self.contractBin})
print("[!] 合约部署预计消耗gas: "+str(gasValue))
tx_hash = eth.contract(
abi=self.contractAbi,
bytecode=self.contractBin).constructor().transact()
receipt=eth.waitForTransactionReceipt(tx_hash)
address = receipt['contractAddress']
#print(dict(receipt))
print("[!] 合约部署成功,地址: "+str(address))
print("[!] 交易详情:"+str((receipt['transactionHash']).hex()))
self.address = address
# 模拟攻击场景
def attack(self):
store_var_contract = self.web3.eth.contract(address=self.address, abi=self.contractAbi)
gas_estimate = store_var_contract.functions.sub_underflow().estimateGas()
print('[!] 调用合约函数 sub_underflow() 消耗gas:'+str(gas_estimate))
print('[!] 合约返回: '+str(store_var_contract.functions.sub_underflow().call()))
if __name__ == "__main__":
''' python deploy.py test.sol'''
contract = contract(sys.argv[1])
contract.deploy()
contract.attack()