地址
- 地址的生成
通常使用Keccak-256来计算公钥的hash,然后只保留最后的20个字节作为地址.
Keccak256(K) = 2a5bc342ed616b5ba5732269001d3f1ef827552ae1114027bd3ecf1f086ba0f9
0x001d3f1ef827552ae1114027bd3ecf1f086ba0f9作为地址.
- 差错检验 (EIP-55)
EIP-55 : 通过修改十六进制地址的大小写,EIP-55为以太坊地址提供了向后兼容的校验和。这个想法是,以太坊地址不区分大小写,所有钱包都应该接受以大写字母或小写字母表示的以太坊地址,在解释上没有任何区别。通过修改地址中字母字符的大小写,我们可以传达一个校验和,可以用来保护地址完整性,防止输入或读取错误。不支持EIP-55校验和的钱包简单地忽略地址包含混合大写的事实。但那些支持它的人可以验证它并以99.986%的准确度检测错误。.
Address: 001d3f1ef827552ae1114027bd3ecf1f086ba0f9
Keccak256("Address"): 23a69c1653e4ebbb619b0b2cb8a9bad49892a8b9...
EIP-55 Address : 001d3F1ef827552Ae1114027BD3ECF1f086bA0F9
我们的地址在第四个位置包含一个字母 d。哈希的第四个字符是 6,小于8。所以,我们保持 d 小写。我们地址中的下一个字母字符是 f,位于第六位。十六进制哈希的第六个字符是 c,它大于8 +。因此,我们在地址中大写 +F,等等。正如你所看到的,我们只使用哈希的前20个字节(40个十六进制字符)作为校验和,因为我们只有20个字节(40个十六进制字符)能正确地大写。
交易
- 特点
- 交易只能由外部账户主动发起. 他是唯一可以触发状态更改或导致合约在EVM中执行的东西.
- 结构
- nonce
- 外部账户发送的交易的数量, 防止消息重播. nonce 只有待处理的交易所在的区块被挖掘之后, 返回的nonce才是正确累加的.
- gas price
- 发起人愿意支付的gas 价格(单位是wei). gas不是以太币, 是独立的虚拟货币, 有相对于以太币的汇率. 以太坊使用gas来控制交易可以花费的资源量. 钱包可以在发起的交易中调整 gas price, 以便更快的确认交易(交易被打包到区块中). gasPrice 越高, 甲乙被验证的速度越快, 相反就越慢. 可以通过计算最近几个区块的中间价格来提供gasPrice的建议价格.
- start gas
- 发起人最大愿意支付的gas量. 如果交易目的地址是外部账户收款地址,以太币从一个外部账户转移到另一个外部账户, 所需的gas量固定Wei 21000个gas. 如果想计算转账消耗的以太币, 需要 gasPrice * startGas, 单位是Wei. 如果交易目的地址是合约地址, 需要估算所需的gas的量, 但是无法准准确确定, 因为合约根据不同的条件, 可能执行不同的指令, 而不同的指令消耗的gas数量是不同的.
- 合约执行前, 会先扣除合约预估消耗的的最大gas, 如果合约执行完成, gas有剩余会返还, 如果执行过程中发现gas不足, 会比较当前消耗的gas和startGas, 看看是否可以继续从startGas扣除, 如果可以就继续扣除需要的, 如果不足就回滚到合约执行之前, 但是gas不会返还, 而是消耗掉了
- 如果合约执行过程中, 报错, 那就扣掉gas, 然后回滚回合约执行前.
- to
- 目标以太坊地址(合约地址或者外部账户地址).以太坊没有进一步验证这个字段。任何20字节的值都被认为是有效的。如果20字节的值对应于没有相应私钥的地址,或没有相应的合约,则该交易仍然有效。以太坊无法知道某个地址是否是从公钥(从私钥导出的)正确导出的, 这样的以太币是永远无法被花费的.
- data
- 变长二进制数据. 和value组合有一下几个情况, 当你的交易包含data时候, 对于目的地址不同,可能有不同的解读(现在对于外部账户地址, 不会解读, 对于合约地址, 可能会有不同的解读, 如果目标地址是合约地址, 但是没有写入data, 那么EVM会调用合约的fallback函数. 后边会介绍);
- value + data
web3.eth.sendTransaction({from: src, to: dst, value: web3.toWei(0.01, "ether"), data: "0x1234"});
- 只有 value, 没有data
web3.eth.sendTransaction({from: src, to: dst, value: web3.toWei(0.01, "ether"), data: ""});
- 只有 data, 没有value
web3.eth.sendTransaction({from: src, to: dst, value: 0, data: "0x1234"});
- 没有value 也没有data
web3.eth.sendTransaction({from: src, to: dst, value: 0, data: ""}));
- 如果想有意识的燃烧一部分ether时候, 可以将目标地址设置为 0x000000000000000000000000000000000000dEaD, 这是专门燃烧ether的地址.
- v, r, s
pragma solidity ^0.4.19;
contract Faucet {
function withdraw(uint withdraw_amount) public {
require(withdraw_amount <= 100000000000000000);
msg.sender.transfer(withdraw_amount);
}
function () public payable {}
}
- 合约注册
- 将合约编译成二进制的十六进制表示 faucet_code =
6060604052341561000f57600080fd5b60e58061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632e1a7d4d146041575b005b3415604b57600080fd5b605f60048080359060200190919050506061565b005b67016345785d8a00008111151515607757600080fd5b3373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151560b657600080fd5b505600a165627a7a72305820d276ddd56041f7dc2d2eab69f01dd0a0146446562e25236cf4ba5095d2ee802f0029
- 注册合约
web3.eth.sendTransaction({from: src, to:0x00, value : 0, data: faucet_code, gas: 113558, gasPrice: 200000000000}) 得到交易的hash0x7bcc327ae5d369f75b98c0d59037eec41d44dfae75447fd753d9f2db9439124b 通过查询交易可以知道合约的地址 0xb226270965b43373e98ffc6e2c7693c17e2cf40b 注册合约时候目标地址: 0x00, value : 0(如果value不是0, 那么这value将无法被花费, 因为这个地址没有对应的私钥);
- 调用合约的函数(发送到合约的 data 是一个十六进制序列化的编码, 函数选择器 : 函数prototype的Keccak256哈希的前4个字节。这使EVM能够明确地识别你希望调用的功能. 函数的参数 : 根据EVM定义的各种基本类型的规则进行编码函数参数)
- 首先需要计算要调用的函数的Keccak256哈希值, 比如上边的withdraw函数,
web3.sha3("withdraw(uint256)"); 得到'0x2e1a7d4d13322e7b96f9a57413e1525c250fb7a9021cf91d1540d5b69f16a49f', 然后计算传递的参数 web3.toWei(0.01, "ether");得到 10000000000000000, 将结果转成16进制得到 0x2386f26fc10000, 最终data内容 2e1a7d4d000000000000000000000000000000000000000000000000002386f26fc10000 , 最终调用函数withdraw表示为 web3.eth.sendTransaction({from: src, to: 0xb226270965b43373e98ffc6e2c7693c17e2cf40b, value:0 , data: "0x2e1a7d4d000000000000000000000000000000000000000000000000002386f26fc10000"});, 当需要向这个合约转账时候将需要转账的金额放在value字段中即可.
token
totalSupply
返回当前存在的Token的总单位。ERC20Token可以有固定或可变的供应量。
balanceOf
给定一个地址,返回该地址的Token余额。
transfer
给定一个地址和数量,将该数量的Tokens从执行该方法的地址的余额转移到该地址。
transferFrom
给定发送者,接收人和数量,将Token从一个帐户转移到另一个帐户。与approve结合使用。
approve
在给定接收者地址和数量的情况下,授权该地址从发布批准的帐户执行多次转账,直到到达指定的数量。
allowance
给定一个所有者地址和一个消费者地址,返回该消费者被批准从所有者的取款的剩余金额。
Transfer event
成功转移时触发的事件(调用transfer或transferFrom)(即使对于零值转移)。
Approval event
成功调用approve时记录的事件。
ERC20 可选函数
name
返回Token的可读名称(例如“US Dollars”)。
symbol
返回Token的人类可读符号(例如“USD”)。
decimals
返回用于分割Token数量的小数位数。例如,如果小数为2,则将Token数除以100以获取其用户表示。
contract ERC20 {
function totalSupply() constant returns (uint theTotalSupply);
function balanceOf(address _owner) constant returns (uint balance);
function transfer(address _to, uint _value) returns (bool success);
function transferFrom(address _from, address _to, uint _value) returns (bool success);
function approve(address _spender, uint _value) returns (bool success);
function allowance(address _owner, address _spender) constant returns (uint remaining);
event Transfer(address indexed _from, address indexed _to, uint _value);
event Approval(address indexed _owner, address indexed _spender, uint _value);
}
网友评论