2018以太坊开发随记
区块链课件
1. 以太坊:一个可以为不同区块链提供服务的平台,开发人员可以再该平台上编写代码,编写属于自己区块链的合约,创建自己的交易规则和状态转移函数
2. 以太坊虚拟机:以太坊的核心,包含点对点的网络协议,各个节点的维护和更新
3. 以太坊账户:以太坊的基本单位就是账户,每个账户由20个(哈希)字节组成,
区块链上发生变化其实就是比特币(或者其他币)的交易和状态的改变。
以太坊有两种账号:外部账号和合约账号,
外部账号(EOA)是个人的账号,由每个人的私钥控制的,
对于合约账号,是由合约代码控制的,其只能由一个EOA账号控制。
合约账号不会做出什么行为,全都靠着外部账号发指令。
一个以太网账号包含四个字段:
1.随机数,确保每个交易只被处理一次
2.账户余额
3.合约代码
4.这个账户的存储
4. 交易:在以太坊中是签名的数据包,包括
1.消息的接收方
2.可识别发送方的签名
3.发送方给接收方的以特币数量
4.可选参数
5.一个STARTGAS,交易允许的最大交易步骤(防止恶意交易,毕竟是有成本的)
6.GASPRICE,计算所耗费的费用
5. 以太坊状态转移函数(真的没看懂)
6. 多重签名:至少两个账号 至少1.02个以太币
7. 以太坊网络type:
1.公有链:任何用户,任何市场,数据一致性
2.私有链:公司内部,写权限由一个组织控制,读权限随意
3.联盟链:数据一致性的运算被预先设定好的几个节点共同控制的链。这样每一次的操作都需要联盟的各个成员验证才能通过
对于开发者而言,大多数使用的是私有链或者联盟链
区块链第三节
第三节要求可以在私链上挖矿
8. 以太坊加快下载速度的op:geth --testnet --fast --cache=1024 --jitvm console
9. 区块链一个区块的信息
CustomGenesis.json
{
"nonce": "0x0000000000000042",
"timestamp": "0x0",
"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x0",
"gasLimit": "0x8000000",
"difficulty": "0x400",
"mixhash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x3333333333333333333333333333333333333333",
"alloc": { }
}
解释:
nonce + mixhash : 被称作工作证明,其中mixhash是256位的哈希值,nonce是64位的哈希值。(至于为什么称为工作证明,可能是符合某个数学条件吧)
timestamp:unix的时间戳
parenthash:顾名思义
extraData:交易过后留下的自己的基本信息比如名字什么的
gaslimit:当前链,一个区块消耗的gas上限
difficulty:定义挖矿的目标,可以由上一区块的难度值和时间戳计算出来(计算方位暂时不详),难度越高,越难挖到矿
alloc:预先放进去一些钱啊
coinbase:160位的钱包地址。在创世区块中可以被定义成任何的地址,因为当每挖到一个区块的时候,这个值会变成矿工的etherbase地址
第四节
0731笔记:
请构建一个多节点的(至少2个节点)私有链网络,并在上面练习多重签名钱包或者子货币合约
1. solidity智能合约教程:一个合约由一组代码(合约的函数)和数据(合约的状态)
2. 关于solidity的基础知识:
1. 状态变量是被永久地保存在合约中。也就是说它们被写入以太币区块链中. 想象成写入一个数据库。
2. solidity支持结构体
3. solidity支持数组
4. 状态变量被永久保存在区块链中。所以在你的合约中创建动态数组来保存成结构的数据是非常有意义的。
5. 结构体数组:“结构体名字[] public 数组名字”
6. 习惯上函数里的变量都是以(_)开头 (但不是硬性规定) 以区别全局变量。我们整个教程都会沿用这个习惯。
7. 私有函数的函数名以_开头
8. 函数的定义中包含返回的数据类型
9. 函数的修饰符:
view:把函数定义为 view, 意味着它只能读取数据不能更改数据:
pure:pure 函数, 表明这个函数甚至都不访问应用里的数据
10. 注意返回不是return 而是returns 是在定义函数的时候
11. 事件 是合约和区块链通讯的一种机制。你的前端应用“监听”某些事件,并做出反应
12. 地址属于特定用户(或智能合约)的
13. 结构体,数组和映射都是存储数据的方法
14. 在 Solidity 中,有一些全局变量可以被所有函数调用。 其中一个就是 msg.sender,它指的是当前调用者(或智能合约)的 address。
15. 我们怎样才能限定每个玩家只调用一次这个函数呢?答案是使用require。 require使得函数在执行过程中,当不满足某些条件时抛出错误,并停止执行
16. 除 public 和 private 属性之外,Solidity 还使用了另外两个描述函数可见性的修饰词:internal(内部) 和 external(外部)。
internal 和 private 类似,不过, 如果某个合约继承自其父合约,这个合约即可以访问父合约中定义的“内部”函数。(嘿,这听起来正是我们想要的那样!)。
external 与public 类似,只不过这些函数只能在合约之外调用 - 它们不能被合约内的其他函数调用。稍后我们将讨论什么时候使用 external 和 public。
0801笔记
17. solidity可以返回多个值,很神奇吧,接收返回值的时候可以酱紫(,,name,,,,id),选择性接收参数
截止到目前为止,第一二课就学习完了
//lesson3
18. 函数修饰符: 关键字modifier类似于function一样,声明一个新的东西,不同的是告诉编辑器这是一个修饰符,只能用在声明函数的后面,经常用在函数之前添加加速的require检查,onlyOwner保护自己的合约不被第三方修改。
函数修饰符可以带自己相带的参数
19. ☆☆☆☆☆☆☆☆所以非常重要的是,部署在以太坊上的 DApp,并不能保证它真正做到去中心,你需要阅读并理解它的源代码,才能防止其中没有被部署者恶意植入后门;作为开发人员,如何做到既要给自己留下修复 bug 的余地,又要尽量地放权给使用者,以便让他们放心你,从而愿意把数据放在你的 DApp 中,这确实需要个微妙的平衡。
20. gas 运行程序都需要花费一定的gas,gas是需要用以太币购买的,所有每次用户运行DApp(去中心化的应用)都需要以特币
21. 代码的优化,越笨拙的代码需要的话费越多
22. solidity代码的优化:当 uint 定义在一个 struct 中的时候,尽量使用最小的整数子类型以节约空间。 并且把同样类型的变量放一起(即在 struct 中将把变量按照类型依次放置),这样 Solidity 可以将存储空间最小化
23。solidity自己的时间单位 now返回当前的unix的时间戳,这个时间戳用32位就足够,但是到了2038年,32位就不能在满足时间戳的长度了,所以这是一个需要两难全的问题mn
24. 结构体的存储指针可以以参数的方式传递给一个 private 或 internal 的函数,因此结构体可以在多个函数之间相互传递。
25. view函数不需要支付gas 666啊
//lesson4 学习payable函数,学习如何开发可以接收其他玩家付款的DApp。
26. 关于函数修饰符:
private:只能被合约内部调用
internal:像private一样,但同时能被继承的合约调用
external:只能从合约外部调用
public:合约的任何地方都可以调用
关于状态修饰符:
view:告诉我们这个函数不会更改和保存任何数据
pure:告诉我们这个函数不仅不会写往区块链数据,他甚至不从区块链读取数据
注意:外部调用不耗费gas,内部调用耗费gas
自定义的函数修饰符,关键词modifier ☆☆☆☆☆☆☆☆切记modifier定义的最后一行是"_;"
一个函数可以有多个自定义修饰符
27. 新的修饰符payable:可以接收以太的函数
//0802 lesson5
代币, ERC721 标准,以及可交易的物件/僵尸
库以及如何使用库
如何利用 SafeMath 来防止溢出和下溢
代码注释和 natspec 标准
28. 在智能合约中通常有一个映射mapping(address=>uint),即通过地址查询改地址还有多少钱
29. solidity可以实现多继承 C++,java也可以实现多继承, 但是PHP只有单继承
30. function balanceOf(address _owner) public view returns (uint256 _balance); 传入地址,返回改地址有多少代币
31. function ownerOf(uint256 _tokenId) public view returns (address _owner);传入代币的ID,返回其拥有者的address
32. 代币的交易有两种方法
1. function transfer(address _to, uint256 _tokenId) public; 这种是coin的发送方把接受者的地址和发送coin的id传进函数直接发送
2. function approve(address _to, uint256 _tokenId) public; 同上,coin的owner调用approve,把receiver的信息和coin的id传入函数
function takeOwnership(uint256 _tokenId) public;接着,该合约会存储谁被允许提取代币,通常存储到一个 mapping (uint256 => address) 里。然后,当有人调用 takeOwnership 时,合约会检查 msg.sender 是否得到拥有者的批准来提取代币,如果是,则将代币转移给他。
33. 合约的安全性:溢出和下溢
34. library 关键字 — 库和 合约很相似,但是又有一些不同。 就我们的目的而言,库允许我们使用 using 关键字,它可以自动把库的所有方法添加给一个数据类型
//lesson6
35. 用 Infura 作为节点提供者,你可以不用自己运营节点就能很可靠地向以太坊发送、接收信息。
var web3 = new Web3(new Web3.providers.WebsocketProvider("wss://mainnet.infura.io/ws"));
36. Metamask 是 Chrome 和 Firefox 的浏览器扩展, 它能让用户安全地维护他们的以太坊账户和私钥, 并用他们的账户和使用 Web3.js 的网站互动
37. 与合约对话:需要合约地址和它的ABI ---应用二进制接口(Application Binary Interface)); Web3.js 为了要和你的智能合约对话而需要的东西是 ABI
38. Web3.js 有两个方法来调用我们合约的函数: call and send.
1. call 用来调用 view 和 pure 函数。它只运行在本地节点,不会在区块链上创建事务。
2. send 将创建一个事务并改变区块链上的数据。你需要用 send 来调用任何非 view 或者 pure 的函数
receipt 将在合约被包含进以太坊区块上以后被触发,这意味着僵尸被创建并保存进我们的合约了。
error将在事务未被成功包含进区块后触发,比如用户未支付足够的gas。我们需要在界面中通知用户事务失败以便他们可以再次尝试。
39. 我们可以通过这样来获取 web3 变量中激活的当前账户:var userAccount = web3.eth.accounts[0];
40. 一个 wei 是以太的最小单位 — 1 ether 等于 10^18 wei 太多0要数了,不过幸运的是 Web3.js 有一个转换工具来帮我们做这件事:// 把 1 ETH 转换成 Wei web3js.utils.toWei("1", "ether");
41. 为了筛选仅和当前用户相关的事件,我们的 Solidity 合约将必须使用 indexed 关键字,
42. 使用 event 和 indexed 字段对于监听合约中的更改并将其反映到 DApp 的前端界面中是非常有用的做法。
43. 查询过去的事件 cryptoZombies.getPastEvents("NewZombie", { fromBlock: 0, toBlock: 'latest' }) 用过滤器 fromBlock 和 toBlock 给 Solidity 一个事件日志的时间范围
44 var web3Infura = new Web3(new Web3.providers.WebsocketProvider("wss://mainnet.infura.io/ws"));
var czEvents = new web3Infura.eth.Contract(cryptoZombiesABI, cryptoZombiesAddress);
45 对于订阅事件还是不太理解,是在html中触发了某个event然后根据返回的结果再处理自己接下来的记录
~~~~~~~~~~~~~~~~~~~PHP以太坊开发~~~~~~~~~~~~~~~~~~~~~~~
1. 以太坊是第一个实现了虚拟机的区块链,因此为智能合约 - Smart Contract的运行提供了良好的支持环境。也正因为这个原因,以太坊被称为区块链2.0,以区别于比特币代表的以数字加密货币为核心特征的区块链1.0。
2. 以太坊作为一个去中心化的系统,必然不会采用中心化的账户管理方案没有一个中心数据库来保存以太坊平台上的所有账户信息。 事实上,以太坊使用非对称密钥技术来进行身份识别,一个以太坊 账户对应着一对密钥:
3.以太坊使用非对称密钥对来进行身份识别,每一个账户都有对应的私钥和公钥,私钥用来签名、公钥则用来验证签名 —— 从而 在非可信的去中心化环境中实现身份验证。
4. 从私钥可以得到公钥,然后进一步得到账户地址,而反之则无效。
5. keystore允许你用加密的方式存储密钥。这是安全性(一个攻击者需要keystore文件和你的钱包口令才能盗取你的资金)和可用性(你只需要keystore 文件和钱包口令就能用你的钱了)两者之间完美的权衡。
6. 采用对称加密算法,当我们需要从keystore中恢复私钥时,只需要使用生成该钱包的密码,并结合keystore文件中的算法参数
7. 口令是不是token的值呢?账户凭证是不是密码?
8. 状态与交易:以太坊上状态的改变和数值的改变
在以太坊中,外部应用可以向节点提交两种交易:普通交易和裸交易。 普通交易由节点签名,而裸交易则由外部应用负责签名。相应的,这两种 交易需要调用不同的接口进行提交。
由于共识机制,向节点提交的交易不会立刻生效,最理想的情况下是被 矿工置入下一个新块。因此交易提交后还需要耐心等待交易收据。
9. 交易类型:普通交易 裸交易
通交易由节点负责签名,然后发送到网络中进行确认;
而裸交易则由外部应用进行签名,节点不再额外处理,而只是负责发送到网络中进行确认 —— 这也是裸交易名称的由来 —— 未经节点加工的原始交易
10. 交易后产生的类似于发票的东西
(
[transactionHash] => 0x5d3ab736571a92ff6cbd6e461d4c894053c066f6ec0ee8ef20f1d28abcdcafc4
[transactionIndex] => 0x0
[blockHash] => 0x2f01de00ccbd63cf7ca0caba7e7df55e3d216858dcb40e14523a94135d3d0cbb
[blockNumber] => 0x10
[gasUsed] => 0x5208
[cumulativeGasUsed] => 0x5208
[contractAddress] =>
[logs] => Array
(
)
[status] => 0x1
[logsBloom] => 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
)
transactionHash: DATA, 32字节 - 交易哈希
transactionIndex: QUANTITY - 交易在块内的索引序号
blockHash: DATA, 32字节 - 交易所在块的哈希
blockNumber: QUANTITY - 交易所在块的编号
from: DATA, 20字节 - 交易发送方地址
to: DATA, 20字节 - 交易接收方地址,对于合约创建交易该值为null
cumulativeGasUsed: QUANTITY - 交易所在块消耗的gas总量
gasUsed: QUANTITY - 该次交易消耗的gas用量
contractAddress: DATA, 20字节 - 对于合约创建交易,该值为新创建的合约地址,否则为null
logs: Array - 本次交易生成的日志对象数组
logsBloom: DATA, 256字节 - bloom过滤器,轻客户端用来快速提取相关日志
返回的结果对象中还包括下面二者之一 :
root : DATA 32字节,后交易状态根(pre Byzantium)
status: QUANTITY ,1 (成功) 或 0 (失败)
11. Gas是指一个transaction 在EVM中执行的步数,类似于数据结构中的复杂度O();
gas price计算公式:
交易手续费(Tx Fee) = 实际运行步数(Actual Gas Used) * 单步价格(Gas Price)
Gas Limit就是一次交易中Gas的可用上限,也就是你的交易中最多会执行多少步运算。 由于交易复杂程度各有不同, 确切的Gas消耗量是在完成交易后才会知道,因此在你提交交易 之前,需要为交易设定一个Gas用量的上限。
一个交易可能被收取的最高服务费就是Gas Limit * Gas Price 了
geth的一些命令:
geth --rpc --rpcapi net,eth,web3,personal,miner --datadir ./data --networkid 7878 --port 30304 console
更改
geth --rpc --rpcapi net,eth,web3,personal --rpcport 30306 --port 8547 --datadir ./data1 --networkid 7878 console
geth --identity "pfx1" --ipcdisable --nodiscover --port 30301 --rpccorsdomain "*" --datadir "chain" --networkid 998 console //在windows下开启
geth --dev console //启动带有好多wei的账户
eth.accounts('12312313') //创建账户
eth.getbalance(eth.accounts[1]) //查看账户有多少钱
personal.unlockAccount(eth.accounts[1])//解锁一下账户
eth.sendTransaction({from: eth.accounts[1], to: eth.accounts[0], value: web3.toWei(100,'ether')})
miner.setEtherbase("0xc65e36d4ec02d4c8a6ca4b33f07dc55b8b800e73") //设置默认挖矿账户
eth.coinbase()//查看默认账户
admin.nodeInfo.enode //查看节点信息
http://shenzhen.weisanyun.cn/blockchain/public/index.php/admin/common/login.html