Hello World
type: channel
link: https://wlwl.host/
description: Just So So ...
items: 支持多链多币的跨链桥
items: 比特币 交易模型
items: RSA 算法
items: 以太坊 再质押
items: 以太坊 交易类型
items: 以太坊 历史
items: Python 虚拟环境
items: stripe 支付
items: Gin 路由和代理
items: 一键静态WEB服务器

支持多链多币的跨链桥
type: item
date: 2024-09-15T15:06:00+00:00
description: 需求分析可以支持多条链，只要链支持Solidity智能合约即可可以支持多个代币，需要符合ERC20标准的代币由去中心化的中继节点采用投票方式来完成跨链请求的确认每个中继节点需要质押保证金，每成功一笔跨链交易可获取奖励引入惩罚机制，中继节点每次作恶都会被罚没，保证金低于一定值时被封禁，重新充入保证金可解封引入黑名单管理机制，符合监管需求，禁止名单内账户使用跨链桥功能引入中继节点准入机制，维持中继节点集群稳定，保障跨链桥的稳定工作跨链交易规则跨链有最低金额限制（比如100USDT）每笔收取总金额的一定比例作为手续费（比如万分之五）一定比例的手续费平分给参与投票的中继节点（比如70%）剩下比例的手续费发给平台（比如30%）用户需手动去领取跨链资产，也可以在指定一个帮忙自动提取的中继节点（需额外付费）中继节点规则中继节点列表由平台进行管理维护，需保持稳定（避免在短时间内大量增加或减少）保证金由中继节点自行维护，存入自由，取出需要限制（比如每隔24小时可取一次）中继节点数量需保持一定合适的数量，至少也得3个，太多中继节点也不好（浪费机器资源，也拖慢投票速度）投票罚没规则中继节点需保证金大于指定门槛的才可以参与投票（比如10万），低于的处于封禁状态中继节点的投票权重都一样，和保证金大小无关每次跨链请求需要大于2/3的中继节点（所有的包括封禁的）投票才算通过投票时需要附带中继节点的签名（合约可以验证签名来核查投票结果并允许用户提取对应资产）每次作恶罚没一定比例的保证金（比如5万），罚没的保证金转给平台地址如果某个节点持续作恶，会不断损失保证金，平台也可以将其从中继节点列表中移除跨链通道要进行跨链交易，需要在两条链之间创建一个通道通道是有方向的，一般情况要添加双向的：A链->B链和B链->A链通道需指定两条链关联的代币地址相同的两条链可添加多对代币地址参与角色普通用户-web前端：发起跨链请求、领取跨链资产、查看交易记录（历史的和进行中的）中继节点-后台服务：跨链交易投票、帮用户自动领取跨链资产中继节点-web前端：查看管理保证金、查看收益、查看投票记录平台管理-web前端：查看管理中继节点、查看保证金、查看收益列表、查看修改黑名单、查看交易记录数据分析与监控：交易汇总分析、中继节点收益分析、资金流动分析、跨链桥异常预警合约设计核心流程：用户在A链存入（冻结）资产、中继节点投票（签名）确认、使用超2/3的签名在B链取出（解冻）资产引入一个廉价的链来存储投票过程，而不是中继节点自行共识，投票过程更安全，也可追溯，提高系统的可用性、安全性用来投票的链这里称为桥链（bridge chain），它还可用来存储一些其它数据或运行一些服务使用签名技术减少合约调用次数，简化设计与节省交易gas费为了节省交易gas费，所有投票在桥链上完成，其它功能也尽量在桥链上实现投票就是签名，用户投票则是将签名写入到桥链合约中跨链通道定义：通道id=keccak256(来源链id,来源链代币地址,目标链id,目标链代币地址)跨链交易定义：交易id=keccak256(通道id,时间戳,接收者,金额,手续费)跨链交易记为KR，投票就是对KR进行签名，记为：KS，有效投票需满足数据无篡改和签名可验证架构桥核心合约（资产）：跨链资金出入口、中继成员列表、黑名单列表桥治理合约（投票）：签名存储与验证、保证金管理、惩罚机制、手续费分发桥链部署：治理合约A链部署：资产合约B链部署：资产合约C链部署：资产合约桥核心合约接口-添加中继节点接口-移除中继节点接口-将账户地址加入黑名单接口-将账户地址从黑名单删除接口-添加跨链通道接口-移除跨链通道接口-跨链转入资产（用户资产充足且未在黑名单内）接口-跨链取出资产（需通过2/3的中继节点签名验证）事件-中继节点变更、黑名单变更、资产转入、资产转出、资产解冻、交易取消查询-中继节点、黑名单、跨链USDT额度（到不同链上的额度）变量-跨链USDT额度列表、中继节点列表、黑名单列表桥治理合约接口-增加保证金接口-减少保证金接口-上传签名（验证签名，作恶罚没）事件-保证金变更、签名提交、投票结果、罚没查询-保证金、签名、罚没次数、罚没金额变量-保证金余额列表、签名列表、跨链交易列表、惩罚记录表合约执行以以太坊和波场为例，以稳定币USDT为例初始化两条链的桥核心合约设置相同的10个中继节点地址和黑名单列表在桥链的桥治理合约中为10个中继节点地址冲入20万保证金平台往两条链的桥核心合约中存入10万USDT作为流动资金Ethereum >>> Tron 跨链用户调用Ethereum链资产合约的跨链转入接口检查用户不在黑名单内，黑名单用户交易直接失败将用户的1万个USDT转到资产合约地址名下更新变量：到Tron链的跨链USDT额度减少1万发出事件：跨链转入（…

比特币 交易模型
type: item
date: 2024-09-01T14:28:00+00:00
description: 与以太坊的账户模型不同，比特币是没有余额概念的，使用的是UTXO模型。所以在比特币网络中，存储比特币的是交易输出，准确点说就是未使用过的交易输出。UTXOUTXO是Unspent Transaction Outputs的缩写（Transaction可简写为TX），即未使用过的交易输出。比特币节点会追踪UTXO集合，从而确定哪些代币未被花费，以及哪些人可以花费它们。最初的比特币是通过铸币交易创造的，它是用来奖励矿工的一种特殊交易，因为是凭空创造的，所以它没有输入的。新的UTXO是通过花费现有UTXO创建的，UTXO包含了接收地址和金额。每个比特币交易都由输入和输出组成。输入花费已有UTXO，输出则创建新的UTXO，UTXO只要被用一次，就不存在“未花费”了，以后就不会再被引用，这样就解决双花（双重支付）问题。当我们要使用一个UTXO时，需要对UTXO进行解锁（一般是用私钥对UTXO进行签名），虽然UTXO是公开的，但是如果没有私钥去解锁，则不能花费UTXO。交易结构交易是比特币的核心数据结构，包括区块在内的数据结构都是在为交易服务。交易主要由未花费的输入和输出组成，输出总金额不能大于输入的总金额，多余的部分为交易矿工费有三种类型交易铸币交易（Generation TX），有额外的Coinbase字段，矿工可以随意填写一些信息，因为是挖矿所得，所以这种交易类型没有输入，输出数量就是矿工所得，地址是矿工的地址。普通交易（Pubkey Hash TX），转账交易，一个或多个输入，一个或两个输出，第一个输出称为支付，第二个输出称为找零脚本交易（Script Hash TX），一般为多签脚本，为普通交易升级版本，可以生成灵活的锁定脚本，然后使用特定的解锁脚本去花费比特币字段表数据项大小(Byte)数据类型描述nVersion4int32_t交易版本vin不定CTxIn列表交易输入vout不定CTxOut列表交易输出nLockTime4uint32_t交易锁定时间交易输入CTxIn数据项大小(Byte)数据类型描述prevout不定COutPoint上一个交易的输出，由交易哈希和索引值确定scriptSig不定char[]解锁脚本nSequence4uint32_t序列号，可用于相对时间锁定交易输出CTxOut数据项大小(Byte)数据类型描述nValue8int64_t交易输出金额，单位为SatoshisscriptPubKey不定char[]锁定脚本，定义花费须满足的条件创币交易CoinbaseTransaction每一个区块内包含的第一条交易为CoinbaseTransaction，它作为对挖出该区块的矿工的比特币奖励交易。没有交易输入交易哈希为0输出的索引值固定，为0xffffffffBIP34规定增加一个4字节的height的字段，这个参数是必须的源码参考代码路径：https://github.com/bitcoin/bitcoin/blob/master/src/primitives/transaction.hCOutPut/** An outpoint - a combination of a transaction hash and an index n into its vout * ** 一个交易哈希值与输出下标的集合 */ class COutPoint { public: uint256 hash; //交易哈西 uint32_t n; //对应序列号 COutPoint(): n((uint32_t) -1) { } COutPoint(const uint256& hashIn, uint32_t nIn): hash(hashIn), n(nIn) { } ADD_SERIALIZE_METHODS; //用来序列化数据结构，方便存储和传输 template <typename Stream, typename Operation> inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(hash); READWRITE(n); } void SetNull() { hash.SetNull(); n = (uint32_t) -1; } bool IsNull() const { return (hash.IsNull() && n == (uint32_t) -1); } //小于号<重载函数 friend bool operator<(const COutPoint& a, const COutPoint& b) { int cmp = a.hash.Compare(b.hash); return cmp < 0 |…

RSA 算法
type: item
date: 2024-08-04T15:24:00+00:00
description: 公钥：e、n，私钥：d、n，加密：C=M^e % n，解密：M=C^d % n。其中：n=p*q（p和q为大质数），1<e<ϕ(n)，gcd(e,ϕ(n))=1，ed % ϕ(n)=1，M为信息，C为密文数论基础质数：又称素数，一个大于1的自然数，除了1和它自身外，不能被其他自然数整除的数模运算：求余运算，整除运算中，求a除以b的余数，可用mod表示，即r = a mod b同余：两个整数a、b，若它们除以正整数m所得的余数相等，则称a、b相对于模m同余，记作: a≡b(mod m)最大公因数：指两个或多个整数共有因数中最大的一个，a和b的最大公因数记作：gcd(a,b)互质：若N个整数的最大公因数是1，我们就称这N个整数互质，即gcd(a,b)=1，a和b互质欧拉函数：对于正整数n，小于n的正整数中与n互质的数的个数，记为ϕ(n)，特别的ϕ(1)=1欧拉定理：若两个正整数a和m互质，那么a的φ(m)次方除以m的余数为1，即a^ϕ(m)≡1(mod m)模反元素：如果两个正整数a和n互质，则一定可以找到整数b，使得a×b-1被n整除，或者说ab≡1(mod n)，称b为a相对于n的模反元素比如，3和11互质，那么3相对于11的模反元素就是4，因为(3 × 4)-1可以被11整除a^(ϕ(n)-1)为a相当于n的模反元素，因a^ϕ(n)≡1(mod n) => a^(1+ϕ(n)-1)≡1(mod n) => a×a^(ϕ(n)-1)≡1(mod n)同余相关性质若a≡b(mod m)，b≡c(mod m)，则a±c≡b±d(mod m)若a≡b(mod m)，b≡c(mod m)，则a×c≡b×d(mod m)若a≡b(mod m)，那么a^n≡b^n(mod m)若a≡b(mod m)，n为m因数,则a≡b(mod n)互质相关性质任意两个质数是互质数较小数是质数，较大数不为它的倍数，这两个数是互质数较大数是质数的两个数是互质数1和任意一个自然数是是互质数2和任何奇数是互质数相邻的两个自然数是互质数相邻的两个奇数是互质数欧拉相关性质ϕ(1)=1，ϕ(2)=1当n是质数时，ϕ(n)=n-1当p为质数时，k为自然数，那么ϕ(p^k)=p^k - p^(k-1)当a和b互质时，ϕ(ab)=ϕ(a)ϕ(b)，故当n是奇数时，ϕ(2n)=ϕ(n)任意一个大于1的正整数，都可以写成一系列质数的积只有p的倍数与p^k互质，共有p^(k-1)个，即1p、2p、3p...p^(k-1)p，把它们去除，剩下的就是与p^k互质的数了，即ϕ(p^k)=p^k - p^(k-1)算法选择两个大质数p和q计算n=p×q，计算欧拉函数ϕ(n)=(p-1)×(q-1)选择一个数e，满足：1<e<ϕ(n)，且e与ϕ(n)互质计算e相对于ϕ(n)的模反元素d，即ed≡1(mod ϕ(n))公钥为{e，n}，私钥为{d，n}加密：C=M^e(mod n)，解密：M=C^d(mod n)，M为信息，C为密文，M需小于nRSA签名可用私钥加密信息摘要，验证者用公钥解密签名，和给出的签名进行一致性判断 *大质数生成随机构造一个满足最终大质数长度的奇数n判断n是不是质数，如果是则输出n，否则n=n+2并重复此步骤使用质数定义判断，将n除以2到n的算术平方根之间的所有数，如果余数都不为0，则此数一定为质数使用素性检测算法（Fermat、Miller–Rabin等等），多次判断此数都为质数的情况下，则此数极大概率为质数查找互质数利用互质特性直接得出结果（两个相邻的自然数是互质数，较小质数与不是倍数的较大数互质）使用辗转相除法计算两个数的最大公约数，如果是1，则两数互质计算模反元素随机选择一个正整数k根据定义：a×b % n = 1，则a相对于n的模反元素b = (k×n + 1) / a快速幕模算法计算a^b%n(a<n)，如果a和b很大，可以使用同余的性质来快速计算结果根据同余性质，有(a × a) % n = (a%n × a%n) % n若b为偶数，则a^b%n = (a^(b/2)%n × a^(b/2)%n) % n若b为奇数，则a^b%n = (a^(b/2)%n × a^(b/2)%n × a) % n令b' = b/2，有a^(b/2)%n = a^b'%n故这里可以使用递归的方式计算a^b%n，不断将b除2，直到1为止安全性随机数：使用完全随机的算法，避免潜在的安全，如果随机数被预测，私钥就有可能被破解密钥长度：为了保持算法的安全性，必须选择足够大的密钥长度，最低需要1024位，推荐使用2048位参数选择：尽量不重复使用大质数p和q，也不要选择太大或太小的e和d证明证明：M=C^d mod n (C=M^e mod n, 0<M<n)C^d mod n 代…

以太坊 再质押
type: item
date: 2024-07-26T12:08:00+00:00
description: Restaking（再质押）是DeFi（去中心化金融）深化发展后的一种复杂产品形态，也是以太坊共识机制转PoS后才出现的新型金融衍生品。一、质押质押的概念出现于区块链的PoS共识机制（Poof of Staking，权益证明）。目前主要有两个主流的共识机制：PoW（Poof of Work，工作量证明）和PoS（Poof of Staking，权益证明）。区块链世界的鼻祖比特币就是采用的 PoW 共识机制。简单说，区块链相当于一个全球化的分布式账本，为了维护这个去中心化系统的运作，需要有人去算账和记账。以太坊区块链最开始也是采用的PoW共识机制，但是PoW也存在一些问题，比如消耗大量电力去计算数学题，没有产生任何对现实世界有价值的收益，而且出现了专门用来挖矿的设备以及具有规模化挖矿的矿场企业，趋向中心化了。因此后来出现了PoS共识机制（Poof of Staking，权益证明），就是想要获得记账权的人把代币质押到一个地方当作保证金，谁持有的代币更多和持有得更久，谁获得记账权的概率就越高，这样大家就不用消耗大量的算力来算没用的数学题了。质押就是让用户锁定一定资金作为保证金后成为节点，去维护项目的安全，从而赚取收益，若节点作恶则会罚没保证金。从技术视角看，质押是为了维持去中心化系统的自我运作PoW是通过算力占比来获得记账权；PoS是通过资产占比来获得记账权；从金融视角看，质押可以控制链上经济系统的货币发行PoW将代币直接奖励给矿工，矿工将链上资产换成现实世界资产买矿机，继续投入挖矿，实现了区块链世界和现实世界的融合；PoS将代币直接奖励给质押者，质押者通过质押资产获取了收益，质押资产变更了具有稳定收益率的 “国债”，衍生了各类金融玩法。质押方案独立质押：运行节点，成为质押者，需要32个ETH，这个是最基本的质押模式；质押即服务：运行节点很麻烦，需要一直在线，因此出现了质押即服务，同样需要32个ETH，但无需运行节点，将节点运作的工作委托给第三方运营商；联合质押32个ETH的门槛还是很高，因此出现了联合质押的平台，不需要32个ETH，每个人可以与其他人一起质押任意数量的 ETH，将节点运作委托给第三方；中心化交易所：使用联合质押的平台还是有一定门槛，用户需要懂得使用区块链应用，同时这类应用可能会存在合约风险，比如智能合约存在漏洞，被黑客攻击等等，因此出现中心化交易所帮助用户进行质押的需求，用户将资金完全交给交易所，交易所进行质押。这四种方案门槛是不断降低的，操作上也越来越简单，这样就可以触达更多的用户，当然，用户资产面临的风险也是越来越大的，越来越不受用户自己掌控。流动性质押（LSD）用户将资产质押了之后，资产就被锁在了链上，此时资金利用效率很低，因此出现了流动性质押平台（Liquid Staking Derivatives，LSD），比如Lido，当你质押了1个ETH，平台会1比1给你一个质押凭证，即1个stETH。这类流动性质押平台一般采用的是联合质押模式，用户可存入任意数量的ETH，帮助用户进行节点质押，用户可获得质押凭证，让用户可在DeFi中进行交易、借贷、提供流动性等操作，提升了资金使用效率。其实这可以类似银行存款，你将现金存到了银行，银行会给你一个存款凭证，然后你可以继续使用这个存款凭证做其他事情，比如交易、抵押借贷等。二、再质押除了区块链采用的PoS机制需要用户质押资产之外，很多项目也都需要Staking来保证项目安全，比如跨链桥、预言机、数据可用性层、零知识证明等。那么，每上线一个新项目，这个项目就需要用户锁定一定的资金，用户的流动资金就那么多，这就造成了不同项目之间的竞争。各个项目为了项目安全性不得不竞争市场上有限的流动资金，随着不同项目给出的质押收益率越来越高，项目自身承担的风险也越来越高，变成了一个恶性循环。另一方面，用户也只能把有限的资金选择有限的项目质押进去获得有限的回报，资金的利用率较低。随着公链、应用、各类项目越来越多，流动性也越来越割裂。因此，市场上出现了 “共享安全性” 的需求，需要有一个平台可以将用户质押的资产为多个项目提供安全性，这就是再质押（Restaking）出现的背景。类比现实世界，一些弱小的国家会引入强大国家的军事力量，自己则无需花费更多的资金构建自己专属的军事力量。目前安全性最强的PoS机制公链就是以太坊，以太坊上质押了大量的资金，具有极强的安全性，因此非常值得将以太坊的安全性共享给其他项目。另一方面，再质押可以为stETH这类质押凭证拓展了更多的应用场景，通过各类协议的可组合性，实现了以太坊生态的 “金融乐高”。再质押定义根据再质押出现的背景以及解决的问题，我们可以给一个再质押的定义：再质押的本质是建立一个共享质押池，从而实现共享安全性。这个共享资金池可以将一份资金同时为多个项目质押…

以太坊 交易类型
type: item
date: 2024-07-13T13:35:00+00:00
description: 以太坊作为一个不断发展的区块链平台，随着时间的推移引入了多个改进提案来提升其性能和用户体验，其交易的数据结构也在一直“进化”交易类型过去，以太坊的交易都采用同一种格式：RLP([nonce, gas_price, gas_limit, to, value, data, v, r, s])在EIP-2718（2021年4月15日柏林（Berlin)升级）改进协议中，定义了一种带交易类型的通用交易格式：TransactionType || TransactionPayload将上述字段连接（合并）起来，即可得到一个类型化交易。字段的定义是：TransactionType：0至0x7f范围内的某个值，最多可代表128种事务类型。TransactionPayload：由事务类型定义的任意一个字节数组。EIP-2718没有为交易的有效负载定义格式。因此，交易的有效负载可以是任意一段经过编码的字节序列，只要采用符合新的交易类型（如RLP、SSZ等）定义的编码器即可。之所以选择简单的字节相连方式，是因为读取字节数组的第一个字节非常简单，无需使用任何库或工具。新的交易类型最多可达0x7f种。选择这一上限是为了保证向后兼容传统交易。经过RLP编码的交易的第一个字节始终大于或等于0xc0，因此类型化交易永远不会与传统交易产生冲突，而且类型化交易和传统交易之间可以通过第一个字节来区分。以太坊目前的源代码中定义了四种交易类型：// Transaction types. const ( LegacyTxType = 0x00 AccessListTxType = 0x01 DynamicFeeTxType = 0x02 BlobTxType = 0x03 )Legacy交易Legacy交易是以太坊早期的交易类型，从链开始持续很长时间都是此类型的交易。特点：Gas价格（Gas Price）：用户设定的固定值，表示愿意为每个Gas单位支付的费用。Gas限额（Gas Limit）：用户愿意为交易支付的最大Gas数量。交易费用：由 Gas Price * Gas Used 计算得出。示例：{ "from": "0xSenderAddress", "to": "0xRecipientAddress", "value": "1000000000000000000", // 1 ETH in Wei "gas": 21000, "gasPrice": "20000000000" // 20 Gwei }AccessList交易EIP-2930（2021年4月15日柏林（Berlin)升级）改进协议，引入了访问列表（Access List）功能，以优化Gas费和提高交易效率。增加了以下格式的交易：0x01 || RLP([chain_id, nonce, gas_price, gas_limit, to, value, data, access_list, y_parity, r, s])特点：访问列表（Access List）：提前声明交易将访问的存储和合约地址，减少Gas费。Gas价格和Gas限额：与Legacy交易类似，但增加了访问列表字段。示例：{ "from": "0xSenderAddress", "to": "0xRecipientAddress", "value": "1000000000000000000", // 1 ETH in Wei "gas": 21000, "gasPrice": "20000000000", // 20 Gwei "accessList": [ { "address": "0xContractAddress", "storageKeys": ["0xStorageKey1", "0xStorageKey2"] } ] }DynamicFee交易EIP-1559（2021年8月5日伦敦（London)升级）改进协议，引入动态费用功能，旨在改善Gas费的预测和用户体验。增加了以下格式的交易：0x02 || RLP([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data, access_list, y_parity, r, s])特点：基础费用（Base Fee）：由网络动态调整，不会支付给矿工，而是被销毁。优先费（Priority Fee）：支付给矿工的费用，类似于小费，以激励矿工优先处理交易。最大费用（Max Fee）：用户愿意支付的最高费用，包括基础费用和优先费。示例：{ "from": "0xSenderAddress", "to": "0xRecipientAddress", "value": "1…

以太坊 历史
type: item
date: 2024-06-22T13:05:00+00:00
description: 说明以太坊区块链主要里程碑、分叉和更新的时间表分叉是区块链协议升级或修改，此时区块链会分成“两条链”，一条链继续使用旧的协议，另一条链则应用新的协议。如果协议向后兼容则为软分叉，否则为硬分叉（新协议可正常处理旧协议生成的区块）关键时间表2015年7月30日以太坊主网启动，开始公测，这个初始版本有诸多限制，在上面能做的事情很少，主要面向开发者。2016年3月14日家园分叉，包括若干协议修改和联网变更，相比初始版本来说稳定很多。2017年10月16日拜占庭升级，将区块挖矿奖励从5个以太币减少到3个以太币，修改完善虚拟机。2019年12月8日伊斯坦布尔分叉，优化了虚拟机中特定操作的燃料成本，添加CHAINID虚拟机指令2020年12月1日信标链启动，使用权益证明机制，未来将会替代以太坊的工作量证明机制2022年9月15日巴黎升级（合并），是以太坊历史上最重要的升级！结束了工作量证明挖矿算法及相关共识逻辑，使用信标链作为共识引擎，一个完整的节点包括执行客户端（原以太坊）和共识客户端。所有时间表2013年11月27日：发布白皮书2014年04月01日：发布黄皮书2014年07月22日：预售以太币2015年07月30日：发布第一个版本，前沿（Frontier）2015年09月07日：200,000区块高度，前沿解冻分叉2016年03月14日：1,150,000区块高度，家园（Homestead）分叉2016年07月20日：1,920,000区块高度，去中心化自治组织（DAO）分叉2016年10月18日：2,463,000区块高度，橘子口哨(Tangerine Whistle)分叉2016年11月22日：2,675,000区块高度，伪龙(Spurious Dragon)分叉2017年10月16日：4,370,000区块高度，拜占庭（Byzantium）升级2019年02月28日：7,280,000区块高度，君士坦丁堡（Constantinople）分叉2019年12月08日：9,069,000区块高度，伊斯坦布尔（Istanbul）分叉2020年01月02日：9,200,000区块高度，缪尔冰川（Muir Glacier）升级2020年10月14日：11,052,984区块高度，部署质押存款合约2020年12月01日：0纪元，信标链创世2021年04月15日：12,244,00区块高度，柏林（Berlin）升级2021年08月05日：12,965,00区块高度，伦敦（London）升级2021年10月27日：74,240纪元，天鹰座（Altair）升级2021年12月09日：13,773,000区块高度，箭形冰川（Arrow Glacier）升级2022年06月30日：15,050,000区块高度，灰色冰川（Gray Glacier）升级2022年09月06日：144,896纪元，Bellatrix升级2022年09月15日：15,537,394区块高度，巴黎（Paris）合并2023年04月12日：17,034,870区块高度（194,048纪元），上海嘉佩乐 (Shapella)升级，包括上海（Shanghai）升级和卡佩拉（Capella）升级2024年03月13日：19,426,587区块高度（269,568纪元），坎昆-天津四(Dencun)升级，包括坎昆（Cancun）升级和天津四（Deneb）升级参考链接：https://ethereum.org/zh/historyhttps://eips.ethereum.org/meta

Python 虚拟环境
type: item
date: 2024-05-28T13:37:00+00:00
description: 默认情况下，Python的依赖包会安装到相同的位置，且不同版本的包不能共存。如果同时开发或运行不同的项目，则可能会存在包冲突问题，要么修改代码使不同的项目都使用相同版本的包，要么使用虚拟环境。Python虚拟环境是一种用于隔离不同Python项目所需依赖的机制。它允许在同一台机器上同时管理多个Python项目，每个项目都可以有自己独立的Python版本和依赖库，互不干扰。使用虚拟环境的好处在于：可以帮我们快速创建干净、完全隔离的且不同版本的Python解释器以便我们能在不同项目中开发；可以避免因在不同项目中只使用唯一的全局解释器而导致的依赖冲突问题（Dependency Conflicts）。激活虚拟环境后，python和pip等命令将作用于虚拟环境一、 venvvenv是Python官方在Python3.3版本开始内置的一个标准库模块，让我们可以快速生成一个虚拟环境。现在我们只要下载的Python 解释器版本在3.3及以上就能直接使用，而无需安装其他依赖。使用它的方式十分简单，只需要通过使用对应版本的Python解释器并运行以下命令即可，比如这里我们以Python 3.10版本解释器为例：$ python3.10 -m venv <your-virtual-environment-name>通常我们在创建虚拟环境时需，要简单指定一个名称用以存放虚拟环境的内容，所以上述代码中的名称通常就保持和venv模块名称一致：$ python3.10 -m venv venv通过对应版本的Python解释器调用venv模块得到的虚拟环境，其版本也与解释器保持一致，也即在创建的venv目录中期Python解释器也为3.10。并且在不指定目录的情况下，默认会在当前运行命令的目录中创建虚拟环境。目前像Pycharm这样的IDE或VS Code类似的文本编辑器（需要安装插件）已经会正确识别到venv目录，并在运行代码时自动帮我们切换到虚拟环境中。但如果我们是在终端上切换虚拟环境，那么就需要自己进行手动激活（Active）。由于venv模块创建的虚拟环境目录在Linux和Windows内容有所不同，所以就导致二者在激活虚拟环境时的命令也有所差异。# Linux $ source venv/bin/activate # Windows $ .\venv\Scripts\activate.bat当然，如果我们想要退出虚拟环境，要么直接关闭IDE，要么直接在终端命令行界面输入deactivate命令即可（或是同样关闭终端）。$ deactivateactivate文件有多个版本，当在windows系统时，如果用CMD时，使用activate.bat；如果用PowerShell时使用activate.psl二、 pipenvpipenv将包管理工具pip和venv有机地结合到了一起，实现了开发环境和生产环境依赖的分离，旨在构建专属于Python的开发工作流，达到类似于npm，yarn等工具的效果。安装:pip install pipenv基本用法：创建环境：pipenv install激活环境：pipenv shell退出环境：exit删除环境：pipenv --rmpipenv install命令会根据系统默认Python版本来创建虚拟环境，并生成用于依赖包管理的Pipfile和Pipfile.lock文件。当你将项目分享给他人的时候，执行pipenv install命令会创建一个虚拟环境并自动安装Pipfile中指定的依赖包。和npm的pack-lock.json类似，pipenv通过依赖描述文件Pipfile来安装和管理依赖项目包管理：安装requests：pipenv install requests安装所有依赖包：pipenv install卸载requests：pipenv uninstall requests卸载所有依赖包：pipenv uninstall --all

stripe 支付
type: item
date: 2024-04-18T13:19:00+00:00
description: stripe一体化全球支付平台，有良好的用户体验和界面设计，支持多种接入方式，且功能比较灵活，也易于集成。注册和API密钥账户注册验证激活访问Stripe网站：https://stripe.com/zh-hk ，并点击登录按钮登录，没有账号的可以先注册一个。填写必要信息：提供您的电子邮件地址、密码等信息以注册账户，并完成身份验证步骤，以确保账户的安全性。集成stripe支付，一开始账户处于开发模式，所有数据都是模拟的，上线时录入商家或公司信息激活账户进入真实模式。API密钥获取登录Stripe控制台：https://dashboard.stripe.com ，使用您的账户信息登录Stripe控制台。进入开发人员界面，单击API密钥选项卡，在下面可以找到公钥和密钥。在开发阶段，使用测试密钥，在生产环境中使用生产密钥，注意保管好密钥。妥善保管这些凭据，并根据需要定期更新它们，以维护支付系统的安全性集成前后端这里使用go语言为后端语言，react为前端语言。一、设置服务器将依赖项添加到您的项目并导入库。go get -u github.com/stripe/stripe-go/v78接下来创建一个结账接口，前端客户请求这个接口时，按客户的要购买的商品来创建一个结账会话，并将这个会话的ClientSecret返回给客户。import ( "log" "net/http" "strconv" "github.com/gin-gonic/gin" "github.com/stripe/stripe-go/v78" "github.com/stripe/stripe-go/v78/checkout/session" ) func init() { // This is your test secret API key. stripe.Key = "sk_test_51P12rrI3yx14f44QTHOPqliw9So8GBpZ6EIPi7v1iDbdlgr5NH0vXIH3zUjQJwxLI7pbAsfSErQOy75sAVr7q4ra00AODgXKD0" } func CreateCheckoutSession(c *gin.Context) { var req struct { Email string `json:"email"` Amount int64 `json:"amount"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "msg": "param decode error:" + err.Error(), }) } params := &stripe.CheckoutSessionParams{ LineItems: []*stripe.CheckoutSessionLineItemParams{ { PriceData: &stripe.CheckoutSessionLineItemPriceDataParams{ Currency: stripe.String("usd"), UnitAmount: stripe.Int64(10000 * req.Amount), ProductData: &stripe.CheckoutSessionLineItemPriceDataProductDataParams{ Name: stripe.String("AI Tools"), }, }, Quantity: stripe.Int64(1), }, }, CustomerEmail: stripe.String(req.Email), Metadata: map[string]string{"email": req.Email, "amount": strconv.Itoa(int(req.Amount))}, Mode: stripe.String(string(stripe.CheckoutSessionModePayment)), UIMode: stripe.String("embedded"), ReturnURL: stripe.String("http://localhost:5173/#/payment?session_id={CHECKOUT_SESSION_ID}"), } s, err := session.New(params) if err != nil { log.Printf("session.New: %v", err) } c.JSON(http.StatusOK, gin.H{ "clientSecret": s.ClientSecret, }) }按客户实际…

Gin 路由和代理
type: item
date: 2024-04-16T14:40:00+00:00
description: 路由Gin路由遵循Restful API接口规范，是基于httproute实现的基本路由语法如下，httpMethod为请求类型，relativePath为路径，handlers为该路由响应函数列表（多个中间件加一个执行函数）router.<httpMethod>(relativePath string, handlers ...HandlerFunc)支持GET、POST、PUT、PATCH、DELETE、OPTIONS等请求类型，Any方法匹配所有类型，Match方法匹配指定的多个类型func main() { router := gin.Default() router.GET("/login", loginEndpoint) router.POST("/login", loginEndpoint) router.Any("/login", loginEndpoint) router.MatchMatch([]string{"POST","GET"}, "/login", loginEndpoint) router.Run(":8080") }路径规则如下"/path"，指定路径，只能匹配/path"/:path"，参数路由，可以匹配/a和/b等，不能匹配/a/b"/*path"，任意路由，可以匹配/、/a和/a/b等所有路由路由按指定路径优先进行匹配，参数路由和任意路由在同一级不可共存func main() { router := gin.Default() // 匹配/user/john但不会匹配/user/或者/user router.GET("/user/:name", func(c *gin.Context) { name := c.Param("name") c.String(http.StatusOK, "Hello %s", name) }) // 将匹配/user/john/和/user/john/send // 如果没有其他路由匹配 /user/john，它将重定向到 /user/john/ router.GET("/user/:name/*action", func(c *gin.Context) { name := c.Param("name") action := c.Param("action") message := name + " is " + action c.String(http.StatusOK, message) }) router.Run(":8080") }路由分组func main() { router := gin.Default() // 简单的路由组: v1 v1 := router.Group("/v1") { v1.POST("/login", loginEndpoint) v1.POST("/submit", submitEndpoint) } // 简单的路由组: v2 v2 := router.Group("/v2") { v2.POST("/login", loginEndpoint) v2.POST("/submit", submitEndpoint) } router.Run(":8080") }路由中间件Gin框架是洋葱结构的，可以同时使用多个中间件，按注册顺序执行，中间件中使用c.Next()函数调用下一个中间件或路由响应函数，如果没有使用c.Next()则执行完此中间件将会返回func Logger() gin.HandlerFunc { return func(c *gin.Context) { t := time.Now() // 请求前 c.Next() // 请求后 latency := time.Since(t) log.Print(latency) } } func main() { r := gin.New() r.Use(Logger()) r.GET("/test", func(c *gin.Context) { }) r.Run(":8080") }中间件可以给指定路由用，比如r.GET("/test", Logger, loginEndpoint)代理拼接真实服务器链接，使用http请求资源，再使用DataFromReader方法返回资源const apiAddr = "https://example.com" func Proxy(c *gin.Context) { url, err := url.Parse(apiAddr + c.Request.URL.Path) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "err": err.Error(), }) }…

一键静态WEB服务器
type: item
date: 2024-04-02T11:05:00+00:00
description: 简化HTTP服务器的配置和管理，使用系统自带的服务，无需安装任何东西，将指定目录作为HTTP服务器的根目录，一键开启静态服务器实现原理Window10和Window11自带PowerShell，使用HttpListener类创建HTTP服务，绑定端口接收请求并返回指定文件。Linux系统自带python，用http.server模块即可创建简易的HTTP服务器。Windows系统实现创建server.ps1文件，并写入如下内容# PowerShell Web Server Param( [parameter(Mandatory=$false)][Int]$port=8080, [parameter(Mandatory=$false)][String]$webPath="www" ) Add-Type -AssemblyName System.Web $scriptPath = $PSScriptRoot $http = [System.Net.HttpListener]::new() $http.Prefixes.Add("http://localhost:$port/") $http.Start() function ConvertTo-Base64($str){ $result = [Convert]::ToBase64String([System.Text.UTF8Encoding]::UTF8.GetBytes($str)) return $result } function ConvertFrom-Base64($str){ $byteArray = [Convert]::FromBase64String($str) return [System.Text.UTF8Encoding]::UTF8.GetString($byteArray) } function Send-WebResponse($context, $content) { if($content.GetType().Name -ne "String"){ $content = ConvertTo-JSON $content } $buffer = [System.Text.Encoding]::UTF8.GetBytes($content) $context.Response.ContentLength64 = $buffer.Length $context.Response.OutputStream.Write($buffer, 0, $buffer.Length) } function Get-PostData{ $reader = new-object System.IO.StreamReader($context.Request.InputStream) $text = $reader.ReadToEnd() # $text = $text.Replace("%3D","=") # $text = ConvertFrom-Base64 $text $text = [System.Web.HttpUtility]::UrlDecode($text) Write-Host "$text" return ConvertFrom-Json $text } if ($http.IsListening) { write-host "HTTP Server Ready! " -f 'black' -b 'gre' write-host "$($http.Prefixes)" -f 'y' } # INFINTE LOOP, Used to listen for requests while ($http.IsListening) { $context = $http.GetContext() $RequestUrl = $context.Request.Url.LocalPath Write-Host "$((Get-Date).ToString('yyyy-MM-dd HH:mm:ss')) : $($context.Request.Url)" -f 'mag' # Get Request Url if ($context.Request.HttpMethod -eq 'GET') { # Redirect root to index.html if($RequestUrl -eq "/") { $RequestUrl = "/index.html" } if(Test-Path "$scriptPath\$webPath\$RequestUrl"){ $fileStream = [System.IO.File]::OpenRead( "$scriptPa…