编译合约
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,sysfrom web3 import Web3,HTTPProviderclass 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.etheth.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()
