区块链的历史
Underground organization : Cypherpunk(密码朋克)
What are we talking about? 数学,加密技术,计算机,数字货币
- 维基解密的创始人阿桑奇
- BT下载的作者的布莱姆-科恩
- WWW的发明者蒂姆伯纳斯-李
- 智能合约概念的提出者:尼克萨博
- Facebook创始人:肖恩帕克
- 中本聪
- Adam Back 发明Hashcash,使用了POW
- Haber/Stornetta 提出时间戳方法保证数字文件安全的协议
- 戴伟发明了B-money,强调点对点交易和不可更改记录
- 哈尔-芬尼推出了“加密现金”
- 2008年中本聪《比特币:一个点对点的电子现金系统》
- 应用场景
- 资产:数字资产发行、支付(跨境支付)、交易、结算
- 记账:股权交易、供应链金融、商业积分
- 不可篡改:溯源、众筹、医疗证明、存在性证明
- 点对点:共享经济,物联网
- 隐私:匿名交易
- 优点
- 财产只受自己控制
- 无通胀
- 没有假钞
- 流通性好
账本如何验证?
- 哈希函数:Hash(原始信息) = 摘要信息
- 同样的原始信息用同一个哈希函数总能得到相同的摘要信息
- 原始信息任何微小的变化都会哈希出面目全非的摘要信息
- 从摘要信息无法逆向推算出原始信息
账号所有权问题
密码->私钥 非对称加密技术(交易签名)
签名和验证是逆运算:付款地址是公钥,签名对摘要进行加密,验证是解密(用付款方地址和签名信息解密)的过程,然后得到交易摘要
补充:没有个人隐私,所以也就无法泄露隐私。安全(不泄露私钥)
为什么记账?
- 记账: Hash打包过程
- 消耗资源
- 奖励
共识机制
两个节点同时完成工作量证明,使用谁的区块?
- 无仲裁机构裁决
- 都说用我的区块
为什么要遵守协议?
- 节点工作量只有在其他的节点认同时其才是有效的
- 累计工作量最大的区块链(独立,延长最长链)
- 工作量证明+最长链 = 使用区块
POW:工作量证明
课下迷思?
- 比特币P2P网络,各个节点之间如何通信(点对点)?
- 区块结构Merkle树
- 比特币UTXO及交易脚本(Unspent Transaction Output未花费过的交易输出)
- 比特币白皮书
区块链技术核心原理实现
不重复了,大家可以看边看视频边看讲师的博客https://learnblockchain.cn/2017/10/27/build_blockchain_by_python/
智能合约编程语言-solidity
文件结构
pragma solidity ^0.4.20;
contract MyToken {
mapping (address => uint256) public balanceOf;
constructor(uint256 initialSupply) public {
balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokens
}
function transfer(address _to, uint256 _value) public {
require(balanceOf[msg.sender] >= _value); // Check if the sender has enough
require(balanceOf[_to] + _value >= balanceOf[_to]); // Check for overflows
balanceOf[msg.sender] -= _value; // Subtract from the sender
balanceOf[_to] += _value; // Add the same to the recipient
}
}
数据类型
- 状态变量 无符号整形uint
- 函数
function setA(uint x) public { a = x; }
- 事件 event Set_A(uint a); 调用事件 emit Set_A(x);
- 结构
struct Pos { int lat; int lng;}
- 函数修改器
modifier owner () {}
修饰函数function mine() public owner{}
在mine函数执行前执行owner中的内容
值类型 Value Type
引用类型(Reference Types)
全局变量和函数
- 有关区块和交易
- msg.sender(address)
- msg.value(uint)
- block.coinbase(address)
- block.difficulty(uint)
- block.number(uint)
- block.timestamp(uint)
- now(uint)
- tx.gasprice(uint)
- 有关错误处理
- 有关数字及加密功能
- 有关地址和合约
错误处理
程序发生错误时的处理方式:solidity的处理方式是回退状态
相关函数:assert(内部逻辑错误),require(外部错误)
发送一半的值
pragma solidity A0.4.20;
contract Sharer{
function sendHalf(address addr)public payable returns (uint balance){
require(msg.value %2==0);
uint balanceBeforeTranfer=this.balance;
addr.transfer(msg.value/2);
assert(this.balance==balanceBeforeTranfer-msg.value/2);
return this.balance;
}
参数
- 输入参数
- 输出参数
- 命名参数 {} 类似python
- 参数解构 元素的值可以赋值给多个变量
contract Test{
function simpleInput(uint a,uint b)
public constant returns (uint sum,uint mul){
sum=a+b;
mul=a*b;
function testSimpleInput()
public constant returns (uint sum,uint mul){
(sum,mul)=simpleInput({ b:3,a:1});
function f()public constant returns (uint,bool,uint){
return (7,true,2);
function g) public {
var (x,y,z) = f();
(x,z) = (z,x);
只取y和z的值
(,y,z) = f();
(x,) = (1,);
}
控制结构
没有switch goto,其他都有
可见性
public
公开函数是合约接口的一部分,可以通过内部,或者消息来进行调用。对于public类型的状态变量,会自动创建一个访问器。函数默认可见性public
private
私有函数和状态变量仅在当前合约中可以访问,在继承的合约内,不可访问。
external
外部函数是合约接口的一部分,只能使用消息调用
在同一个合约中可以使用this(消息调用)来调用
如果我们只接收外部调用的话,我们应该使用external
internal
函数和状态变量只能通过内部访问。如在当前合约中调用,或继承的合约里调用。状态变量默认的可见性是internal
不能在其他的合约中调用
函数
- 构造函数
- 视图函数(constant/view(优先)) 不会修改状态变量
- 纯函数(pure) 不读取变量,也不修改变量
- 回退函数 无名函数,被动调用函数
- 其实public也是一个函数,因为会自动创建一个访问器
contract Test{
uint internal data;
constructor (uint a)public{
data=a;
event EVENTA(uint a);
function testView()public view returns(uint){
//data=1;
// emit EVENTA(1);
return data;
}
function f()public pure returns(uint){
return 1*2;
}
有另一个合约向Test合约转账,就需要下面的callback函数
function ()public payablel{
}
}
contract Caller {
function callTest(Test test) public {
test.send(ether);
}
}
区块链去中心化应用开发
简单代币合约
pragma solidity ^0.4.20;
contract MyToken {
保存每一个账户的余额情况
mapping (address => uint256) public balanceOf;
constructor(uint256 initialSupply) public {
把余额给创建者
balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokens
}
代币转移
function transfer(address _to, uint256 _value) public {
require(balanceOf[msg.sender] >= _value); // Check if the sender has enough
require(balanceOf[_to] + _value >= balanceOf[_to]); // Check for overflows
balanceOf[msg.sender] -= _value; // Subtract from the sender
balanceOf[_to] += _value; // Add the same to the recipient
}
}
标准代币合约
这个是根据20版本来写的,当时是最新版,现在已经更新到
pragma solidity ^0.4.20;
contract ERC20Interface {
string public name;
string public symbol;
uint8 public decimals;
uint public totalSupply;
function transfer(address _to, uint256 _value) returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
function approve(address _spender, uint256 _value) returns (bool success);
function allowance(address _owner, address _spender) view returns (uint256 remaining);
交易发生时的事件
event Transfer(address indexed _from, address indexed _to, uint256 _value);
委托行为发生时的事件
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
contract ERC20 is ERC20Interface {
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) internal allowed;
constructor() public {
totalSupply = 100000000;
name = "MUKE Token";
symbol = "IMOOC";
decimals = 0;
balanceOf[msg.sender] = totalSupply;
}
function balanceOf(address _owner) view returns (uint256 balance) {
return balanceOf[_owner];
}
function transfer(address _to, uint _value) public returns (bool success) {
require(_to != address(0));
require(_value <= balanceOf[msg.sender]);
require(balanceOf[_to] + _value >= balanceOf[_to]);
balanceOf[msg.sender] -= _value;
balanceOf[_to] += _value;
emit Transfer(msg.sender, _to, _value);
return true;
}
function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
require(_to != address(0));
require(_value <= balanceOf[_from]);
require(_value <= allowed[_from][msg.sender]);
require(balanceOf[_to] + _value >= balanceOf[_to]);
balanceOf[_from] -= _value;
balanceOf[_to] += _value;
allowed[_from][msg.sender] -= _value;
emit Transfer(_from, _to, _value);
return true;
}
允许另外一个人操作我的账户
function approve(address _spender, uint256 _value) returns (bool success) {
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
查询被委托了多少个代币
function allowance(address _owner, address _spender) view returns (uint256 remaining) {
return allowed[_owner][_spender];
}
}
npm i -g truffle
truffle init
合约部署
var Adoption = artifacts.require("Adoption");
module.exports = function(deployer) {
deployer.deploy(Adoption);
};
配置truffle
执行命令 truffle migrate
合约测试用例
pragma solidity ^0.4.17;
import 'truffle/Assert.sol';
import 'truffle/DeployedAddresses.sol';
import '../contracts/Adoption.sol';
contract TestAdoption {
拿到测试合约
Adoption adoption = Adoption(DeployedAddresses.Adoption());
判断是否可以领养宠物
function testUserCanAdoptPet() public {
uint returnedId = adoption.adopt(8);
uint expected = 8;
Assert.equal(returnedId, expected, "Aoption of pet Id 8 should be recorded.");
}
// 测试领养地址
function testGetAdopterAddressByPetid() public {
address expected = this;
address adopter = adoption.adopters(8);
Assert.equal(adopter, expected, "Owner of pet ID 8 should be recorded.");
}
// 测试所有的领养者
function testGetAdopterAddressByPetIdInArray() public {
address expected = this;
address[16] memory adopters = adoption.getAdopters();
Assert.equal(adopters[8], expected, "Owner of Pet Id 8 should be recoded.");
}
}
热门评论
很棒的文章