【主要内容】
今天开始第一次尝试使用python来自己部署的智能合约进行交互。学习共用时35分钟。
(此外整理作笔记花费了约74分钟)
详细学习过程见文末学习过程屏幕录像。
【学习笔记】
一、尝试理解gas相关的的一些术语
从以下博文获取了帮助:
https://blog.csdn.net/jfkidear/article/details/82699808
当然仍然没有完全理解,摘录笔记如下:
1.什么是gas
gas是“燃料”的意思,在以太坊区块链上实现了一个EVM(以太坊虚拟机)的代码运行环境,在链上执行写入操作时,网络中的每个全节点都会进行相同的计算并存储相同的值,这种执行的消耗是昂贵的,为了促使大家将能在链下进行的运算都不放到链上进行,也为了奖励矿工,因此在链上每执行一个写入操作时,都需要支付一定的费用,用gas为单位来计数,每个在链上可以执行的命令都设置了一个消耗的gas值,例:PUSH操作需要消耗3个gas,一次转账一般要消耗21000gas,gas使用ETH来支付。
注意:无论您执行的命令是成功还是失败,都需要支付计算费用,即使失败,节点也验证并执行了您的交易(计算),因此必须和成功执行支付一样的费用
2.什么是gas limit
每个区块有gas limit,即单个区块允许的最多gas总量,以此可以用来决定单个区块中能打包多少笔交易。
我们每一次交易或合约调用都要设置一个gas limit,如果该次操作所使用的gas数量小于或等于您所设置的gas limit,则会被执行,但如果gas总消耗量超过gas limit,所有的操作都会被重置,但费用依旧会被收取。在执行中实际消耗的gas值总和叫gas used,没有使用完的gas会退还到原账号。
如果您尝试将一个会使用超过当前区块gas limit的交易打包,则会被网络拒绝,会反馈“below gas limit”
3.什么是gas price
在发起交易或合约调用时,我们可以自己设置gas的价格,即gas price,一般以GWei(1 ETH = 1000000000 GWei)为单位。通过gas price可以节省矿工费用,但也会减慢矿工打包的速度,矿工会优先打包gas price设置高的交易,如果您想加快转账,您可以把gas price设置得更高,这样您就可以插队靠前。
在定义gas price时候,推荐浏览https://ethgasstation.info/ 这里能看到以太坊区块链上最近完成的交易对应的消耗单价、记录时间、等待时间、手续费均价等。根据自身交易需求,我们可以参考右下Safelow/Standard/Fast三个速度对应的gasPrice。
4.总结
gas limit由我们自己设定,相当于我们预计汽车需要加多少升汽油;
gas price由我们自己设定,相当于每升汽油的价格;
一次交易或调用实际需要消耗的gas(gas used)由该次交易或调用过程中执行的命令决定;
gas used 必须小于或等于gas limit;
实际支付的费用 = gas used * gas price。
二、修改并批注第一个可以与eth网络上的自己发布的合约进行交互的py程序
```
#来自博文:https://blog.csdn.net/mongo_node/article/details/85043799
import time
from web3 import Web3, HTTPProvider
contract_address="0xfbf6d79f50219505ff8e10b2f0ca1435a1210ffc" #提供服务的合约地址,就是我自己创建(部署)的智能合约
wallet_private_key="D8EF07D32389148E9DA6C54237BD5A39C92917D59340AA5D6064485C01E96FB2" #狐狸钱包的私钥
wallet_address="0x5227C3EF48B5A1bcF784593e46D9579D26a3b592" #狐狸钱包的公钥,就是钱包地址,是eth网络上的一个节点。
w3 = Web3(HTTPProvider("https://ropsten.infura.io/v3/79124269dc454e47bee73f964c971d3c")) #里面的参数字符串是在infura.io网站上申请 到的一个节点地址。
w3.eth.enable_unaudited_features() #确认我们知道可能会发生问题的情况。
print(w3.eth.blockNumber) #打印eth网络最后一个区块的id
def send_ether_to_contract(amount_in_ether):
#此函数唯一的参数amount_in_ether的计量单位是:wei
amount_in_wei = w3.toWei(amount_in_ether,'ether')
nonce = w3.eth.getTransactionCount(wallet_address) #此处vscode提示eth下层对象不存在,是误报错误,因为web3类在定义时,它的下层对象是通过代码软性加载的,所以vscode无法检测到。
'''
web3类软性加载它的一些下层对象的代码如下:所以vscode通过静态代码去查找这些下层以对象是找不到的,所以报错。
for module_name, module_class in modules.items():
module_class.attach(self, module_name)
module_class中就包含了包括eth在内的多个web3类的下层对象。
以上是花了大量时间查找思考 后的个人见解,可能有错,恳请高手指点。
'''
#一次交易信息的内容如下:
txn_dict={
'to': contract_address, #合约地址,我们是向我自己创建的合约地址发送eth
'value': amount_in_wei, #要发送的eth的数量
'gas': 2000000, #油费,这篇文章讲得很清楚:https://blog.csdn.net/jfkidear/article/details/82699808
'gasPrice': w3.toWei('40','gwei'), #单位油价
'nonce': nonce, #这是一个地址nonce而不是更常见的工作证明。它只是发送地址所做的先前交易次数的计数,用于防止双重花费。
'chainId': 3 #每个以太坊网络都有自己的链ID:主网的ID为1,而Ropsten为3。你可以在这里找到更长的列表。
}
signed_txn = w3.eth.account.signTransaction(txn_dict, wallet_private_key) #用我这个节点(就是我的狐狸钱包这个节点)的私钥对我发出的交易信息进行签名。
#上一行代码,没有通过,签名时失败,提示如下:
'''
File "G:w10_1pythonpython365libsite-packageseth_utilsdecorators.py", line 17, in _wrapper
return self.method(obj, *args, **kwargs)
File "G:w10_1pythonpython365libsite-packageseth_accountaccount.py", line 435, in signTransaction
) = sign_transaction_dict(account._key_obj, sanitized_transaction)
File "G:w10_1pythonpython365libsite-packageseth_accountinternalsigning.py", line 23, in sign_transaction_dict
unsigned_transaction = serializable_unsigned_transaction_from_dict(transaction_dict)
File "G:w10_1pythonpython365libsite-packageseth_accountinternal ransactions.py", line 35, in serializable_unsigned_transaction_from_dict
assert_valid_fields(transaction_dict)
File "G:w10_1pythonpython365libsite-packageseth_accountinternal ransactions.py", line 140, in assert_valid_fields
raise TypeError("Transaction had invalid fields: %r" % invalid)
TypeError: Transaction had invalid fields: {'to': '0xfbf6d79f50219505ff8e10b2f0ca1435a1210ffc'}
'''
txn_hash = w3.eth.sendRawTransaction(signed_txn.rawTransaction) #现在将我这个节点发起的交易信息发送到eth网络上,这个时候,返回一个此交易的唯一hash值,可以随时使用此哈希来查询我这个节点发起的这个交易是否已经被写入到一个挖出来 的区块中了
txn_receipt = None #用于记录智能合约返回给此次交易的收据?
count = 0
while txn_receipt is None and (count < 30):
txn_receipt = w3.eth.getTransactionReceipt(txn_hash) #getTransactionReceipt方法返回指定交易的收据对象。 如果交易处于pending状态,则返回null。
'''
此博文的描述:(注意这是js版本的,没有找到中文py版本的说明)
web3.eth.getTransactionReceipt()方法返回指定交易的收据对象。 如果交易处于pending状态,则返回null。
调用:
web3.eth.getTransactionReceipt(hash [, callback])
参数:
hash:String - 交易的哈希值
callback:Function - 可选的回调函数,其第一个参数为错误对象,第二个参数为结果
返回值:
一个Promise对象,其解析值为交易的收据对象或者null。收据对象具有如下字段:
status - Boolean: 成功的交易返回true,如果EVM回滚了该交易则返回false
blockHash 32 Bytes - String: 交易所在块的哈希值
blockNumber - Number: 交易所在块的编号
transactionHash 32 Bytes - String: 交易的哈希值
transactionIndex - Number: 交易在块中的索引位置
from - String: 交易发送方的地址
to - String: 交易接收方的地址,对于创建合约的交易,该值为null
contractAddress - String: 对于创建合约的交易,该值为创建的合约地址,否则为null
cumulativeGasUsed - Number: 该交易执行时所在块的gas累计总用量
gasUsed- Number: 该交易的gas总量
logs - Array: 该交易产生的日志对象数组
'''
print(txn_receipt)
time.sleep(10)
count+=1
if txn_receipt is None:
return {'status':'失败','error':'超时'}
return {'status':'发送成功,交易完成','txn_receipt':txn_receipt}
dicresult=send_ether_to_contract(20000000000000000)
print(dicresult)
```
结果没有测试通过,在上文代码批注部分出错,暂且没有找到原因。详情见我的学习过程屏幕录像。
【学习后记】
学到今天才算开始进入主题,28天就过去了,时间真如流水,而为了生存,为了换取金钱来养活自己和家人的工作,让我没有办法有更多的时间来学习,做自己喜欢做的事情,这是多么可悲的一幕。突然明白,真正自由是时间的自由,可是人生苦短,出发得太迟。
我从编程世界的完全门外汉走到今天,每一步是很缓慢且不断踩坑,但是这是完全自学必经的道路,那么不自学不是更好吗?我非常赞同一句话——真正的学习就是自学。
过去20年我积累完整的自学方法论,历经实践验证,我正准备在我创建的【就是要学 终身成长】社群中与大家分享讨论这一话题,欢迎立志于终身学习,终身成长的朋友们加入社群,共同交流学习。Qq群号码:646854445
或访问:www.941xue.com
【关于坚持自学的例行说明】
最后例行说明下,我为什么要坚持自学。
“如果我不曾见过太阳,我本可以忍受黑暗,然而阳光已使我的荒凉,成为更新的荒凉。”
——艾米莉·狄金森
如果要问我对自己的前半生如何看待时,我想昨天和今天的答案都将完全不同。
昨天的我,生活在荒凉的满意之中,自觉怡然自得,拿着包身包月的工资,听着仁慈的命令,过着几乎一成不变的生活;时而与周遭的人儿和睦互往,时而唇舌相抵斤斤计较,演出着生活的鸡毛蒜皮,工作的吹拉弹唱;忘我,忘我,才能融入这平和无奇的乐章中,迈着细碎的步伐,原地踏步。那时的我觉得这就是悠然自得的听天由命的平凡人生,也就是我的宿命了。
可是某一天,我见到了不一样的太阳以及太阳下不一样的人生光景——那并不荒凉。
今天的我,生活在荒凉的痛苦之中,自觉渴望改变,迈着不知所措的步伐,看着流逝的年华,睁着悔恨错失一切的双眼… …
我知道我将再无法回到过去的我,只有改变才是唯一正确的方向。
一、为什么一把年纪还在学习
放弃很多去聚餐,去HI歌,去游玩,去看电影,去追剧……的时间,然后进行着这个年纪似乎已不应当再进行的学习,引来身边人们无尽的不解与鄙夷甚至可怜……
但我不想放弃终身学习的誓言。
因为——
我对我今天的生活现状并不认同!
罗伯特清崎告诉过我们,反省自己当下的生活是不是自己想要的,这难道不是最好的动力与答案?
走过了大半生,然后才发现曾经、当下所正在进行的人生并不是自己想要的,那是一种怎样的体验?
只有心中真切的感受才能回答这个问题,而任凭再丰富的语言也是无法描绘出来的。
经历半生的跋涉,却发现走得并不正确,有多少人有勇气承认自己过去的一切都是错误的呢?
而我愿意告诉过去的我:“你错了!”
那么已经历半生错误,年岁之大又压于头顶,还有希望从这架的梯子的半端重新爬下,再蹒跚着爬上另一架梯子吗?
我宁愿相信还有希望!
这便是我为什么要继续坚持终身学习下去的全部理由。
二、这个年纪还在学这些技术有意义吗
纯的技术对这把年纪其实已没有意义。
但兴趣可以超越意义。
但技术可以引来思想的变革,这才是意义。
投资自己的头脑 ,改革自己的思想,这是最保值,更长远的投资,过去我从来没有投资过,错过太多,那就从投资自己头脑开始吧。
罗伯特清崎告诉我们,真正的富有是时间的富有;真正的自由是可以决定自己愿意做什么的自由。
因为我愿意做我兴趣所在的事,所以我希望我有自由选择的那一天,虽然今天离那一天可能还是那么遥远,但我愿意相信,每天多赶几步,离希望就更近一步。
再者,虽然我可能再已无法完全完整的掌握这些技术了,但技术本身却可以启迪心的觉醒,激发灵感,那么只要多了解一点,我相信我将离那个正离我而去跑得越来越快的未来更近一点,不至于被未知的那个未来抛弃得太远。
于是我怎能放弃追逐求索的步伐?
我要坚信:感觉太迟的时候,也许还不算太迟。
感谢一直以来关注我,鼓励我的你!
若不嫌弃这一个到了高龄才长大的可笑可叹的我,请不吝赐教。
我的q号是:578652607,敬候你的指点。
【同步语音笔记】
https://www.ximalaya.com/keji/19103006/265641862
【学习过程屏幕录屏】
链接:https://pan.baidu.com/s/1kESwMCmQgHWL_A-lMUxWPA
提取码:mmpi