以太坊上的几种签名: eth_sign, personal_sign, eth_signTypedData
以太坊的签名算法是ECDSA-secp256k1,以下介绍的每一种签名都是基于该算法,只是用来签名的数据不同。1 交易签名 eth_sign以太坊上,签名之前的交易结构如下。let transaction = { to: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', value: ethers.utils.parseEther('1'), data: '0xE0A293E08F72454CEd99E1769c3ebd21fD2C20a1', gasLimit: '22000', maxFeePerGas: ethers.utils.parseUnits('20', 'gwei'), maxPriorityFeePerGas: ethers.utils.parseUnits('5', 'gwei'), nonce: 1, type: 2, chainId: chainId, // 31337 } 各项目的含义不再介绍,有兴趣可以查阅https://ethereum.org/en/developers/docs/transactions/...
Solidity学习-可升级合约(Transparent/UUPS/Beacon)
以太坊合约原生并不支持升级,目前的升级一般是采用代理模式实现的。代理模式在代理模式中,有2个合约:Proxy和Implementation,用户总是和Proxy进行交互。Proxy在收到用户的调用请求后,并不执行自身的代码,而是通过delegatecall去执行Implementation合约的代码。delegatecall的特殊之处就是,它并不切换上下文,因此Implementation的代码所处理的存储空间是Proxy合约的存储空间,而非自己的。 Proxy合约里存储了Implementation合约的地址,这个地址是可修改的,当我们需要进行合约升级的时候,只需要重新部署一个新的Implementation合约,同时把Proxy合约中存储的地址改成新合约的地址就行了。升级前后,合约的存储空间没有任何变化(依然是Proxy的存储空间),地址也没有变化(依然是Proxy的地址),因此升级过程对用户完全透明。 合约升级之后,要保证storage变量的兼容性。新版本可以在旧版本的变量之后增加新的变量,但是不可以删除或者修改旧版本的变量。因为自始自终,变量都只存储在Proxy合约里,升...
用golang开发ethereum
之前看到一个用golang开发以太坊的教程 https://goethereumbook.org/zh/ 这个教程非常详细,然而它太陈旧了,目前很多go-ethereum函数接口已经有所修改。最明显的是,EIP1559之后,交易的格式的已经大不一样。因此,我基于上述教程,依据最新的go-ethereum(v1.10.26)对代码demo进行了修改。 用golang开发以太坊的一个好处是,可以很方便的查看和调试geth的源码,可以帮助我们更深入地理解以太坊的底层实现。 代码库为 https://github.com/CryptoRbtree/goeth-client 下面对主要功能做简单介绍。1 账户首先需要调用ethclient.DialContext连接一个rpc,这个rpc可以是外部服务商提供的公链rpc,也可以是本地区块链的。var ( ctx = context.Background() url = "https://eth-mainnet.g.alchemy.com/v2/" + os.Getenv("ALCHEMY_ID") client, err = ethclie...
以太坊上的几种签名: eth_sign, personal_sign, eth_signTypedData
以太坊的签名算法是ECDSA-secp256k1,以下介绍的每一种签名都是基于该算法,只是用来签名的数据不同。1 交易签名 eth_sign以太坊上,签名之前的交易结构如下。let transaction = { to: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', value: ethers.utils.parseEther('1'), data: '0xE0A293E08F72454CEd99E1769c3ebd21fD2C20a1', gasLimit: '22000', maxFeePerGas: ethers.utils.parseUnits('20', 'gwei'), maxPriorityFeePerGas: ethers.utils.parseUnits('5', 'gwei'), nonce: 1, type: 2, chainId: chainId, // 31337 } 各项目的含义不再介绍,有兴趣可以查阅https://ethereum.org/en/developers/docs/transactions/...
Solidity学习-可升级合约(Transparent/UUPS/Beacon)
以太坊合约原生并不支持升级,目前的升级一般是采用代理模式实现的。代理模式在代理模式中,有2个合约:Proxy和Implementation,用户总是和Proxy进行交互。Proxy在收到用户的调用请求后,并不执行自身的代码,而是通过delegatecall去执行Implementation合约的代码。delegatecall的特殊之处就是,它并不切换上下文,因此Implementation的代码所处理的存储空间是Proxy合约的存储空间,而非自己的。 Proxy合约里存储了Implementation合约的地址,这个地址是可修改的,当我们需要进行合约升级的时候,只需要重新部署一个新的Implementation合约,同时把Proxy合约中存储的地址改成新合约的地址就行了。升级前后,合约的存储空间没有任何变化(依然是Proxy的存储空间),地址也没有变化(依然是Proxy的地址),因此升级过程对用户完全透明。 合约升级之后,要保证storage变量的兼容性。新版本可以在旧版本的变量之后增加新的变量,但是不可以删除或者修改旧版本的变量。因为自始自终,变量都只存储在Proxy合约里,升...
用golang开发ethereum
之前看到一个用golang开发以太坊的教程 https://goethereumbook.org/zh/ 这个教程非常详细,然而它太陈旧了,目前很多go-ethereum函数接口已经有所修改。最明显的是,EIP1559之后,交易的格式的已经大不一样。因此,我基于上述教程,依据最新的go-ethereum(v1.10.26)对代码demo进行了修改。 用golang开发以太坊的一个好处是,可以很方便的查看和调试geth的源码,可以帮助我们更深入地理解以太坊的底层实现。 代码库为 https://github.com/CryptoRbtree/goeth-client 下面对主要功能做简单介绍。1 账户首先需要调用ethclient.DialContext连接一个rpc,这个rpc可以是外部服务商提供的公链rpc,也可以是本地区块链的。var ( ctx = context.Background() url = "https://eth-mainnet.g.alchemy.com/v2/" + os.Getenv("ALCHEMY_ID") client, err = ethclie...
Share Dialog
Share Dialog
Subscribe to rbtree
Subscribe to rbtree
我们可以在官方的白皮书中查到,mint鞋子的时候,生成各种鞋子的概率。
https://whitepaper.stepn.com/game-fi-elements/shoe-minting

按照上面的概率规则,如果每次mint的时候,大家都是任选2双鞋,那么一代一代地递推下去,最终每种鞋子的比例会是多少呢?
首先,我们假定第0代鞋子中,四种鞋子的概率分别是pW0, pJ0, pR0, pT0。然后我们需要随机挑选两双鞋子mint,这里会产生上面表格里描述的10种组合,可以很容易地算出这10种组合出现的概率。
def getPairRandom(pW0, pJ0, pR0, pT0):
pWW = pW0 * pW0
pWJ = 2 * pW0 * pJ0
pWR = 2 * pW0 * pR0
pWT = 2 * pW0 * pT0
pJJ = pJ0 * pJ0
pJR = 2 * pJ0 * pR0
pJT = 2 * pJ0 * pT0
pRR = pR0 * pR0
pRT = 2 * pR0 * pT0
pTT = pT0 * pT0
return pWW, pWJ, pWR, pWT, pJJ, pJR, pJT, pRR, pRT, pTT
对应每一种组合,我们可以依据官方给出的概率表格来计算下一代出现每一种鞋子的概率。于是可以很容易算出下一代鞋子中各鞋型的占比。
def nextGeneration(pW0, pJ0, pR0, pT0):
pWW, pWJ, pWR, pWT, pJJ, pJR, pJT, pRR, pRT, pTT = getPairRandom(pW0, pJ0, pR0, pT0)
pW1 = pWW * 0.85 + pWJ * 0.45 + pWR * 0.45 + pWT * 0.80 + pJJ * 0.06 + pJR * 0.07 + pJT * 0.06 + pRR * 0.06 + pRT * 0.06 + pTT * 0.25
pJ1 = pWW * 0.06 + pWJ * 0.45 + pWR * 0.07 + pWT * 0.06 + pJJ * 0.85 + pJR * 0.45 + pJT * 0.80 + pRR * 0.06 + pRT * 0.06 + pTT * 0.25
pR1 = pWW * 0.06 + pWJ * 0.07 + pWR * 0.45 + pWT * 0.06 + pJJ * 0.06 + pJR * 0.45 + pJT * 0.06 + pRR * 0.85 + pRT * 0.80 + pTT * 0.25
pT1 = pWW * 0.03 + pWJ * 0.03 + pWR * 0.03 + pWT * 0.08 + pJJ * 0.03 + pJR * 0.03 + pJT * 0.08 + pRR * 0.03 + pRT * 0.08 + pTT * 0.25
return pW1, pJ1, pR1, pT1
对上面的过程反复迭代,最终各种鞋子的比例应该会稳定在某个比例上,下面我们来计算一下。
我们不知道初始的鞋型比例,不妨假定它们都是25%。


可以看到,T鞋的比例很快稳定在3.35%,其他3种鞋子则稳定在32.22%。
其实,初始比例是无关紧要的,最终收敛的稳定值与之无关,我们可以对其他的初始比例做些验证。

可见,最终T鞋的比例都是3.35%,剩下的比例基本上被另外3种鞋均分。
上面假定mint的时候选取的鞋子是随机的,但实际情况可能有所偏差。mint鞋子的偏好一定会对结果有影响的。举个极端的例子,如果大家都只用T鞋mint,那么最终,4种鞋子的比例都会是25%。
我们可以看一个特例,如果大家都只用同类型鞋子mint,会如何呢?这个很容易计算,只需要把鞋子配对的函数改一下就行了。
def getPairSpecific(pW0, pJ0, pR0, pT0):
pWW = pW0
pWJ = 0
pWR = 0
pWT = 0
pJJ = pJ0
pJR = 0
pJT = 0
pRR = pR0
pRT = 0
pTT = pT0
return pWW, pWJ, pWR, pWT, pJJ, pJR, pJT, pRR, pRT, pTT
最终结果如下:


其实和随机配对的结果很接近,只是T鞋的比例略有提高。
游戏中的鞋子如果不转出,是不会上链的,所以我们目前无法得知不同类型鞋子的真实占比情况。我们去OpenSea上看一下,不过要知道这只是全部鞋子中很小的一部分。
https://opensea.io/collection/stepn

W、J、R、T的占比分别为41.09%、31.82%,23.55,3.54%。可以发现W比上面算出的结果高了很多,而R比上面算出的结果小了很多?为什么呢?可能大家觉得runner不好卖,所以不太愿意用R来mint?
不管怎么说,T鞋的占比都是非常低的,只有3.5%左右。之前看到有人说,T鞋的往往都不是T鞋生的,这是当然的,因为非T鞋的数量是T鞋的30多倍,而T鞋生出T鞋的概率才只是非T鞋的8倍。
我们可以在官方的白皮书中查到,mint鞋子的时候,生成各种鞋子的概率。
https://whitepaper.stepn.com/game-fi-elements/shoe-minting

按照上面的概率规则,如果每次mint的时候,大家都是任选2双鞋,那么一代一代地递推下去,最终每种鞋子的比例会是多少呢?
首先,我们假定第0代鞋子中,四种鞋子的概率分别是pW0, pJ0, pR0, pT0。然后我们需要随机挑选两双鞋子mint,这里会产生上面表格里描述的10种组合,可以很容易地算出这10种组合出现的概率。
def getPairRandom(pW0, pJ0, pR0, pT0):
pWW = pW0 * pW0
pWJ = 2 * pW0 * pJ0
pWR = 2 * pW0 * pR0
pWT = 2 * pW0 * pT0
pJJ = pJ0 * pJ0
pJR = 2 * pJ0 * pR0
pJT = 2 * pJ0 * pT0
pRR = pR0 * pR0
pRT = 2 * pR0 * pT0
pTT = pT0 * pT0
return pWW, pWJ, pWR, pWT, pJJ, pJR, pJT, pRR, pRT, pTT
对应每一种组合,我们可以依据官方给出的概率表格来计算下一代出现每一种鞋子的概率。于是可以很容易算出下一代鞋子中各鞋型的占比。
def nextGeneration(pW0, pJ0, pR0, pT0):
pWW, pWJ, pWR, pWT, pJJ, pJR, pJT, pRR, pRT, pTT = getPairRandom(pW0, pJ0, pR0, pT0)
pW1 = pWW * 0.85 + pWJ * 0.45 + pWR * 0.45 + pWT * 0.80 + pJJ * 0.06 + pJR * 0.07 + pJT * 0.06 + pRR * 0.06 + pRT * 0.06 + pTT * 0.25
pJ1 = pWW * 0.06 + pWJ * 0.45 + pWR * 0.07 + pWT * 0.06 + pJJ * 0.85 + pJR * 0.45 + pJT * 0.80 + pRR * 0.06 + pRT * 0.06 + pTT * 0.25
pR1 = pWW * 0.06 + pWJ * 0.07 + pWR * 0.45 + pWT * 0.06 + pJJ * 0.06 + pJR * 0.45 + pJT * 0.06 + pRR * 0.85 + pRT * 0.80 + pTT * 0.25
pT1 = pWW * 0.03 + pWJ * 0.03 + pWR * 0.03 + pWT * 0.08 + pJJ * 0.03 + pJR * 0.03 + pJT * 0.08 + pRR * 0.03 + pRT * 0.08 + pTT * 0.25
return pW1, pJ1, pR1, pT1
对上面的过程反复迭代,最终各种鞋子的比例应该会稳定在某个比例上,下面我们来计算一下。
我们不知道初始的鞋型比例,不妨假定它们都是25%。


可以看到,T鞋的比例很快稳定在3.35%,其他3种鞋子则稳定在32.22%。
其实,初始比例是无关紧要的,最终收敛的稳定值与之无关,我们可以对其他的初始比例做些验证。

可见,最终T鞋的比例都是3.35%,剩下的比例基本上被另外3种鞋均分。
上面假定mint的时候选取的鞋子是随机的,但实际情况可能有所偏差。mint鞋子的偏好一定会对结果有影响的。举个极端的例子,如果大家都只用T鞋mint,那么最终,4种鞋子的比例都会是25%。
我们可以看一个特例,如果大家都只用同类型鞋子mint,会如何呢?这个很容易计算,只需要把鞋子配对的函数改一下就行了。
def getPairSpecific(pW0, pJ0, pR0, pT0):
pWW = pW0
pWJ = 0
pWR = 0
pWT = 0
pJJ = pJ0
pJR = 0
pJT = 0
pRR = pR0
pRT = 0
pTT = pT0
return pWW, pWJ, pWR, pWT, pJJ, pJR, pJT, pRR, pRT, pTT
最终结果如下:


其实和随机配对的结果很接近,只是T鞋的比例略有提高。
游戏中的鞋子如果不转出,是不会上链的,所以我们目前无法得知不同类型鞋子的真实占比情况。我们去OpenSea上看一下,不过要知道这只是全部鞋子中很小的一部分。
https://opensea.io/collection/stepn

W、J、R、T的占比分别为41.09%、31.82%,23.55,3.54%。可以发现W比上面算出的结果高了很多,而R比上面算出的结果小了很多?为什么呢?可能大家觉得runner不好卖,所以不太愿意用R来mint?
不管怎么说,T鞋的占比都是非常低的,只有3.5%左右。之前看到有人说,T鞋的往往都不是T鞋生的,这是当然的,因为非T鞋的数量是T鞋的30多倍,而T鞋生出T鞋的概率才只是非T鞋的8倍。
<100 subscribers
<100 subscribers
No activity yet