Introductory to Blockchain & Solidity 最后更新时间:2022年07月23日 ## Blockchain > https://www.runoob.com/w3cnote/blockchain-intro.html > > 目前我们转账都是中心化的,银行是一个中心化账本,例如 A 账号里有 400 块钱,B 账号里有 100 块钱。 > > 当 A 要转 100 块钱给 B 时,A 要通过银行提交转账申请,银行验证通过后,就从 A 账号上扣除 100 块,B 账号增加 100 块。 > > 计算后 A 账号扣除 100 后余额为300元,B 账号加上 100 后余额为 200 元。 > > 区块链上转账的步骤则是:A 要转账给 B 100 块钱,A 就会在网络上把要转账的这个信息告诉大家,大家会去查看 A 的账户上是否有足够的钱去完成这个转账,如果验证通过后,大家就把这个信息都记录到自己的电脑上区块链中,且每个人记入的信息都是同步一致的,这样 A 就顺利将 100 块钱转移到了 B 的账户上。可以看到这中间并没有银行啥事。 > > ### 有没一两句话能说明白区块链的? > > 有的。 > > 麻将作为中国传统的区块链项目,四个矿工一组,先碰撞出13个数字正确哈希值的矿工可以获得记账权并得到奖励。 > https://zh.wikipedia.org/zh-cn/区块链 > > Many [live-service games](https://en.wikipedia.org/wiki/Games_as_a_service) offer in-game customization options, such as character skins or other in-game items, which the players can earn and trade with other players using in-game currency. Some games also allow for trading of virtual items using real-world currency, but this may be illegal in some countries where video games are seen as akin to gambling, and has led to [gray market](https://en.wikipedia.org/wiki/Gray_market) issues such as [skin gambling](https://en.wikipedia.org/wiki/Skin_gambling), and thus publishers typically have shied away from allowing players to earn real-world funds from games.[[101\]](https://en.wikipedia.org/wiki/Blockchain#cite_note-Verge-Valve-101) Blockchain games typically allow players to trade these in-game items for cryptocurrency, which can then be exchanged for money.[[102\]](https://en.wikipedia.org/wiki/Blockchain#cite_note-inverse_blockchain_games-102) ## Solidity > https://docs.soliditylang.org/en/latest/ > https://solidity-by-example.org > https://solidity-cn.readthedocs.io/zh/develop/index.html > > Solidity 是一门面向合约的、为实现智能合约而创建的高级编程语言。这门语言受到了 C++,Python 和 Javascript 语言的影响,设计的目的是能在以太坊虚拟机(EVM)上运行。 > > Solidity 是静态类型语言,支持继承、库和复杂的用户定义类型等特性。 #### SimpleStorage ```solidity pragma solidity ^0.4.0; // solidity version this program uses contract SimpleStorage { //contract 即合约 uint storedData; function set(uint x) public { //simillar to C++ //Rectangle::Rectangle(double a,double b){width=a;height=b;} storedData = x; } function get() public view returns (uint) { return storedData; } } ``` #### firstApplication ```solidity // compiler version must be greater than or equal to 0.8.13 and less than 0.9.0 // SPDX-License-Identifier: MIT pragma solidity ^0.8.13; contract Counter { uint public count; // Function to get the current count function get() public view returns (uint) { return count; } // Function to increment count by 1 function inc() public { count += 1; } // Function to decrement count by 1 function dec() public { // This function will fail if count = 0 count -= 1; } } ``` #### Subcurrency(子货币) ```solidity pragma solidity ^0.4.21; contract Coin { // 关键字“public”让这些变量可以从外部读取 address public minter; mapping (address => uint) public balances; // 轻客户端可以通过事件针对变化作出高效的反应 event Sent(address from, address to, uint amount); // 这是构造函数,只有当合约创建时运行 function Coin() public { minter = msg.sender; } function mint(address receiver, uint amount) public { if (msg.sender != minter) return; balances[receiver] += amount; } function send(address receiver, uint amount) public { if (balances[msg.sender] < amount) return; balances[msg.sender] -= amount; balances[receiver] += amount; emit Sent(msg.sender, receiver, amount); } } ``` `address public minter;` 这一行声明了一个可以被公开访问的 `address` 类型的状态变量。 `address` 类型是一个160位的值,且不允许任何算数操作。这种类型适合存储合约地址或外部人员的密钥对。关键字 `public` 自动生成一个函数,允许你在这个合约之外访问这个状态变量的当前值。如果没有这个关键字,其他的合约没有办法访问这个变量。由编译器生成的函数的代码大致如下所示: ``` function minter() returns (address) { return minter; } ``` `mapping (address => uint) public balances;` 也创建一个公共状态变量,但它是一个更复杂的数据类型。 该类型将address映射为无符号整数。 Mappings 可以看作是一个 [哈希表](https://en.wikipedia.org/wiki/Hash_table) 它会执行虚拟初始化,以使所有可能存在的键都映射到一个字节表示为全零的值。 但是,这种类比并不太恰当,因为它既不能获得映射的所有键的列表,也不能获得所有值的列表。 因此,要么记住你添加到mapping中的数据(使用列表或更高级的数据类型会更好),要么在不需要键列表或值列表的上下文中使用它,就如本例。 而由 `public` 关键字创建的getter函数 [getter function](https://solidity-cn.readthedocs.io/zh/develop/contracts.html#getter-functions) 则是更复杂一些的情况, 它大致如下所示: ``` function balances(address _account) public view returns (uint) { return balances[_account]; } ``` 正如你所看到的,你可以通过该函数轻松地查询到账户的余额。 `event Sent(address from, address to, uint amount);` 这行声明了一个所谓的“事件(event)”,它会在 `send` 函数的最后一行被发出。用户界面(当然也包括服务器应用程序)可以监听区块链上正在发送的事件,而不会花费太多成本。一旦它被发出,监听该事件的listener都将收到通知。而所有的事件都包含了 `from` , `to` 和 `amount` 三个参数,可方便追踪事务。 为了监听这个事件,你可以使用如下代码: ``` Coin.Sent().watch({}, '', function(error, result) { if (!error) { console.log("Coin transfer: " + result.args.amount + " coins were sent from " + result.args.from + " to " + result.args.to + "."); console.log("Balances now:\n" + "Sender: " + Coin.balances.call(result.args.from) + "Receiver: " + Coin.balances.call(result.args.to)); } }) ``` 这里请注意自动生成的 `balances` 函数是如何从用户界面调用的。 特殊函数 `Coin` 是在创建合约期间运行的构造函数,不能在事后调用。 它永久存储创建合约的人的地址: `msg` (以及 `tx` 和 `block` ) 是一个神奇的全局变量,其中包含一些允许访问区块链的属性。 `msg.sender` 始终是当前(外部)函数调用的来源地址。 最后,真正被用户或其他合约所调用的,以完成本合约功能的方法是 `mint` 和 `send`。 如果 `mint`被合约创建者外的其他人调用则什么也不会发生。 另一方面, `send` 函数可被任何人用于向他人发送币 (当然,前提是发送者拥有这些币)。记住,如果你使用合约发送币给一个地址,当你在区块链浏览器上查看该地址时是看不到任何相关信息的。因为,实际上你发送币和更改余额的信息仅仅存储在特定合约的数据存储器中。 ### Introduction From UoB Dr Remi Chehab  #### naiveBallot.sol ```solidity // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; /** * @title Ballot * @dev Implements voting process along with vote delegation */ contract Ballot { struct Voter { // if true, that person can vote // if true, that person already voted // index of the voted proposal } struct Proposal { // short name for the proposal // number of accumulated votes } // store the chair person // store the voters // store the proposals /** * @dev Initialise the contract and register chairperson. */ constructor() { // save the sender as the chairperson // make the chairperson a voter } /** * @dev Give 'voter' the right to vote on this ballot. May only be called by 'chairperson'. * @param voter address of voter */ function giveRightToVote(address voter) public { require( , "Only chairperson can give right to vote." ); require( , "The voter has already been registered." ); require( , "The voter already voted." ); // give permission to vote } /** * @dev Add a new proposal. * @param name name of proposal */ function addProposal(string memory name) public { require( , "Only voters can add new proposals." ); // save the new proposal } /** * @dev Give your vote to proposal 'proposals[proposal].name'. * @param proposal index of proposal in the proposals array */ function vote(uint proposal) public { Voter storage sender = voters[msg.sender]; require( , "Has no right to vote" ); require( , "Already voted." ); // mark that the sender has voted // save the vote of the sender // increase the votes of the selected proposal } /** * @dev Computes the winning proposal taking all previous votes into account. * @return winningProposal_ index of winning proposal in the proposals array */ function winningProposal() public view returns (uint winningProposal_) { /* go through all the proposals and find the one with the most votes */ } /** * @dev Calls winningProposal() function to get the index of the winner contained in the proposals array and then * @return winnerName_ the name of the winner */ function winnerName() public view returns (string memory winnerName_) { // return the name of the winning proposal } } ``` #### solved_naiveBallot.sol ```solidity // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; /** * @title Ballot * @dev Implements voting process along with vote delegation */ contract Ballot { struct Voter { bool allowed; // if true, that person can vote bool voted; // if true, that person already voted uint vote; // index of the voted proposal } struct Proposal { string name; // short name for the proposal uint voteCount; // number of accumulated votes } address public chairperson; // store the chair person mapping(address => Voter) public voters; // store the voters Proposal[] public proposals; // store the proposals /** * @dev Initialise the contract and register chairperson. */ constructor() { chairperson = msg.sender; // save the sender as the chairperson voters[chairperson].allowed = true; // make the chairperson a voter } /** * @dev Give 'voter' the right to vote on this ballot. May only be called by 'chairperson'. * @param voter address of voter */ function giveRightToVote(address voter) public { require( msg.sender == chairperson, "Only chairperson can give right to vote." ); require( voters[voter].allowed == false, "The voter has already been registered." ); require( !voters[voter].voted, "The voter already voted." ); voters[voter].allowed = true; // give permission to vote } /** * @dev Add a new proposal. * @param name name of proposal */ function addProposal(string memory name) public { require( voters[msg.sender].allowed == true, "Only voters can add new proposals." ); proposals.push(Proposal({ name: name, voteCount: 0 })); // save the new proposal } /** * @dev Give your vote to proposal 'proposals[proposal].name'. * @param proposal index of proposal in the proposals array */ function vote(uint proposal) public { Voter storage sender = voters[msg.sender]; require( sender.allowed = true, "Has no right to vote" ); require( !sender.voted, "Already voted." ); sender.voted = true; // mark that the sender has voted sender.vote = proposal; // save the vote of the sender proposals[proposal].voteCount += 1; // increase the votes of the selected proposal } /** * @dev Computes the winning proposal taking all previous votes into account. * @return winningProposal_ index of winning proposal in the proposals array */ function winningProposal() public view returns (uint winningProposal_) { /* go through all the proposals and find the one with the most votes */ uint winningVoteCount = 0; for (uint p = 0; p < proposals.length; p++) { if (proposals[p].voteCount > winningVoteCount) { winningVoteCount = proposals[p].voteCount; winningProposal_ = p; } } } /** * @dev Calls winningProposal() function to get the index of the winner contained in the proposals array and then * @return winnerName_ the name of the winner */ function winnerName() public view returns (string memory winnerName_) { winnerName_ = proposals[winningProposal()].name; // return the name of the winning proposal } } ```
Comments | NOTHING