面向企业的区块链教程(一)(3)

简介: 面向企业的区块链教程(一)

创建一个创世块

IBFT 工具可以自动创建创世块。同时,它还会生成节点密钥、从节点密钥生成的地址和 static-nodes.json 文件。

运行以下命令以生成所有这些内容:

./istanbul setup --num 4 --nodes --verbose
• 1

现在,你会得到类似的输出:

validators
{
 "Address": "0x05a6245732c2350ba2ed64e840394c2239f8ad1f",
 "Nodekey": "eae5093e524bf14ba6e95c13591d6a785be9ea486b9e8e9c1281314f75a3d4f9",
 "NodeInfo":     "enode://bd1049d796f1b71bef17d428ce8db5f22e478ecbeb9513c57e90d93ca1e9ec107f4f4b43585556ca8bb3ab630f1f6543d0d4147f5d890e1fde301b2af1fd7a08@0.0.0.0:30303?discport=0"
}
{
 "Address": "0x97a80dc7a7e27f41ae006fa1253f1f105f77335c",
 "Nodekey": "decc1787fda1f4079511bcff92e83f868755c8e06636303c42cfb3cce554919e",
 "NodeInfo":     "enode://6344e12a9b3f4fd5c154ee13ebe5351a5460a44302fd493a5e742adf8a294b6dc112fab1fa8ff19dde0027373c96c51ab6254153877c9fadabfc057624e522f0@0.0.0.0:30303?discport=0"
}
{
 "Address": "0xf69faf33e8690e82b0043e9131e09bbbc394cbed",
 "Nodekey": "7e1a7660f4ec525096ebea34a7a3b78803138fbaaa3f61b7dc13439ce3e08c95",
 "NodeInfo": "enode://0955966accd8f36256e876790c9b66098675f7ac6bfc10b805d7356d66844cf696902b8dadb62c44cdb783db69197ebacc709ab1908229fe7e13be3f1eae35fe@0.0.0.0:30303?discport=0"
}
{
 "Address": "0x68795d3e326b553dc8b2c5739b87a9cb827037c8",
 "Nodekey": "9f0e0b268671c29c43a0976faa7e08fd20aae24219ad1db6dfc7e645413600c1",
 "NodeInfo": "enode://a76bf5be8ddd1b1b9bd8d46e5947ccef9c1ce492d4e8fe800e234e61be67a0dbd586e33afb4e17998dc53fa2ea5c72a8a0544c7baae45fc4c16c401c1de90a22@0.0.0.0:30303?discport=0"
}
static-nodes.json
[
 "enode://bd1049d796f1b71bef17d428ce8db5f22e478ecbeb9513c57e90d93ca1e9ec107f4f4b43585556ca8bb3ab630f1f6543d0d4147f5d890e1fde301b2af1fd7a08@0.0.0.0:30303?discport=0",
 "enode://6344e12a9b3f4fd5c154ee13ebe5351a5460a44302fd493a5e742adf8a294b6dc112fab1fa8ff19dde0027373c96c51ab6254153877c9fadabfc057624e522f0@0.0.0.0:30303?discport=0",
 "enode://0955966accd8f36256e876790c9b66098675f7ac6bfc10b805d7356d66844cf696902b8dadb62c44cdb783db69197ebacc709ab1908229fe7e13be3f1eae35fe@0.0.0.0:30303?discport=0",
 "enode://a76bf5be8ddd1b1b9bd8d46e5947ccef9c1ce492d4e8fe800e234e61be67a0dbd586e33afb4e17998dc53fa2ea5c72a8a0544c7baae45fc4c16c401c1de90a22@0.0.0.0:30303?discport=0"
]
genesis.json
{
 "config": {
 "chainId": 2017,
 "homesteadBlock": 1,
 "eip150Block": 2,
 "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
 "eip155Block": 3,
 "eip158Block": 3,
 "istanbul": {
 "epoch": 30000,
 "policy": 0
 }
 },
 "nonce": "0x0",
 "timestamp": "0x5a213583",
 "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000f89af8549405a6245732c2350ba2ed64e840394c2239f8ad1f9497a80dc7a7e27f41ae006fa1253f1f105f77335c94f69faf33e8690e82b0043e9131e09bbbc394cbed9468795d3e326b553dc8b2c5739b87a9cb827037c8b8410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0",
 "gasLimit": "0x47b760",
 "difficulty": "0x1",
 "mixHash": "0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365",
 "coinbase": "0x0000000000000000000000000000000000000000",
 "alloc": {
 "05a6245732c2350ba2ed64e840394c2239f8ad1f": {
 "balance": "0x446c3b15f9926687d2c40534fdb564000000000000"
 },
 "68795d3e326b553dc8b2c5739b87a9cb827037c8": {
 "balance": "0x446c3b15f9926687d2c40534fdb564000000000000"
 },
 "97a80dc7a7e27f41ae006fa1253f1f105f77335c": {
 "balance": "0x446c3b15f9926687d2c40534fdb564000000000000"
 },
 "f69faf33e8690e82b0043e9131e09bbbc394cbed": {
 "balance": "0x446c3b15f9926687d2c40534fdb564000000000000"
 }
 },
 "number": "0x0",
 "gasUsed": "0x0",
 "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19
• 20
• 21
• 22
• 23
• 24
• 25
• 26
• 27
• 28
• 29
• 30
• 31
• 32
• 33
• 34
• 35
• 36
• 37
• 38
• 39
• 40
• 41
• 42
• 43
• 44
• 45
• 46
• 47
• 48
• 49
• 50
• 51
• 52
• 53
• 54
• 55
• 56
• 57
• 58
• 59
• 60
• 61
• 62
• 63
• 64
• 65
• 66
• 67
• 68
• 69
• 70

你会看到不同的地址、enode 等。现在,创建 static-nodes.jsongenesis.jsonenode 密钥文件,并将前述内容放入其中。将节点密钥文件名设为 enode_id_1enode_id_2enode_id_3enode_id_1。将 enode URL 中的端口更改为 23000230012300223003

现在,让我们生成一个以太坊账户,并在创世块中分配一些以太币给它。以太币不是动态生成的,因此我们需要预先提供。使用以下命令生成以太坊账户:

./geth --datadir ./accounts account new
• 1

现在,将 accounts/keystore 目录中的文件名更改为 key1。然后将地址复制,放入 genesis 文件中,并分配一些余额。例如,如果我新生成的账户地址是 0x65d8c00633404140986e5e23aa9de8ea689c1d05,那么我的 genesis 文件内容将如下所示:

{
     "config": {
         "chainId": 2017,
         "homesteadBlock": 1,
         "eip150Block": 2,
         "eip150Hash": 
           "0x000000000000000000000000000000000000000000
            0000000000000000000000",
         "eip155Block": 3,
         "eip158Block": 3,
         "istanbul": {
             "epoch": 30000,
             "policy": 0
         }
     },
     "nonce": "0x0",
     "timestamp": "0x5a213583",
     "extraData": "0x00000000000000000000000000000000000000000000
       00000000000000000000f89af8549405a6245732c2350ba2ed64e840
       394c2239f8ad1f9497a80dc7a7e27f41ae006fa1253f1f105f77
       335c94f69faf33e8690e82b0043e9131e09bbbc394cbed9468795
       d3e326b553dc8b2c5739b87a9cb827037c8b841000000000000000
       0000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000
       00000000000000000000000c0",
     "gasLimit": "0x47b760",
     "difficulty": "0x1",
     "mixHash": "0x63746963616c2062797a616e74696e65206661756c7
       420746f6c6572616e6365",
     "coinbase": "0x0000000000000000000000000000000000000000",
     "alloc": {
         "05a6245732c2350ba2ed64e840394c2239f8ad1f": {
             "balance": "0x446c3b15f9926687d2c40534fdb564000000000000"
         },
         "68795d3e326b553dc8b2c5739b87a9cb827037c8": {
             "balance": "0x446c3b15f9926687d2c40534fdb564000000000000"
         },
         "97a80dc7a7e27f41ae006fa1253f1f105f77335c": {
             "balance": "0x446c3b15f9926687d2c40534fdb564000000000000"
         },
         "f69faf33e8690e82b0043e9131e09bbbc394cbed": {
             "balance": "0x446c3b15f9926687d2c40534fdb564000000000000"
         },
         "65d8c00633404140986e5e23aa9de8ea689c1d05": {
             "balance": "0x446c3b15f9926687d2c40534fdb564000000000000"
         }
     },
     "number": "0x0",
     "gasUsed": "0x0",
     "parentHash": "0x00000000000000000000000000000
       00000000000000000000000000000000000"
}
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19
• 20
• 21
• 22
• 23
• 24
• 25
• 26
• 27
• 28
• 29
• 30
• 31
• 32
• 33
• 34
• 35
• 36
• 37
• 38
• 39
• 40
• 41
• 42
• 43
• 44
• 45
• 46
• 47
• 48
• 49
• 50
• 51
• 52

起始节点

现在,在我们启动节点之前,我们需要初始化它们:为每个节点创建数据目录,将账户密钥复制到数据目录,复制验证者的 enode 密钥,并使用创世块引导区块链。

以下是为所有六个节点实现这些的命令:

#Configuring Node 1
mkdir -p qdata/node1/{keystore,geth}
cp accounts/keystore/key1 qdata/node1/keystore
cp static-nodes.json qdata/node1
cp enode_id_1 qdata/node1/geth/nodekey
./geth --datadir qdata/node1 init genesis.json 
#Configuring Node 2
mkdir -p qdata/node2/geth
cp static-nodes.json qdata/node2
cp enode_id_2 qdata/node2/geth/nodekey
./geth --datadir qdata/node2 init genesis.json 
#Configuring Node 3
mkdir -p qdata/node3/geth
cp static-nodes.json qdata/node3
cp enode_id_3 qdata/node3/geth/nodekey
./geth --datadir qdata/node3 init genesis.json 
#Configuring Node 4
mkdir -p qdata/node4/geth
cp static-nodes.json qdata/node4
cp enode_id_4 qdata/node4/geth/nodekey
./geth --datadir qdata/node4 init genesis.json 
#Configuring Node 5
mkdir -p qdata/node5/geth
cp static-nodes.json qdata/node5
./geth --datadir qdata/node5 init genesis.json 
#Configuring Node 6
mkdir -p qdata/node6/geth
cp static-nodes.json qdata/node6
./geth --datadir qdata/node6 init genesis.json 
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19
• 20
• 21
• 22
• 23
• 24
• 25
• 26
• 27
• 28
• 29
• 30
• 31
• 32
• 33
• 34

上述命令是不言自明的。对于最后两个节点,我们没有生成任何 enode 密钥,因为 geth 如果不存在,则会自动生成一个。现在,运行以下命令启动 Quorum 节点。在新的 shell 窗口中运行每个命令:

./geth --datadir qdata/node1 --mine --port 23000 --ipcpath "./geth.ipc" --istanbul.requesttimeout 5000 --istanbul.blockperiod 1 --istanbul.blockpausetime 20 console
./geth --datadir qdata/node2 --mine --port 23001 --ipcpath "./geth.ipc" --istanbul.requesttimeout 5000 --istanbul.blockperiod 1 --istanbul.blockpausetime 20 console
./geth --datadir qdata/node3 --mine --port 23002 --ipcpath "./geth.ipc" --istanbul.requesttimeout 5000 --istanbul.blockperiod 1 --istanbul.blockpausetime 20 console
./geth --datadir qdata/node4 --mine --port 23003 --ipcpath "./geth.ipc" --istanbul.requesttimeout 5000 --istanbul.blockperiod 1 --istanbul.blockpausetime 20 console
./geth --datadir qdata/node5 --port 23004 --ipcpath "./geth.ipc" console
./geth --datadir qdata/node6 --port 23005 --ipcpath "./geth.ipc" console
• 1
• 2
• 3
• 4
• 5
• 6
• 7

下面是我们刚刚传递的不同选项的含义:

  • 在运行验证者时需要 --mine
  • --istanbul.requesttimeout 是最大区块时间(默认值:10000ms)。
  • --istanbul.blockperiod 是最小区块时间(默认值:1s)。
  • --istanbul.blockpausetime 是前一个区块中没有交易时的暂停时间。值应大于 istanbul.blockperiod(默认值:2s)。

要获取网络中所有验证者的列表,您可以使用 istanbul.getValidators() API。

动态添加或移除验证者

让我们首先看看如何动态添加新的验证节点。要添加验证节点,我们首先需要生成新验证节点的节点密钥和地址。运行以下命令生成它:

./istanbul setup --num 1 --nodes --verbose
• 1
• 2

这是我们之前使用的相同命令。现在,我们不需要 genesis 文件或 static-nodes.json 文件。我们只需要节点密钥和地址。创建一个名为 node_id_5 的文件,并将节点密钥放入其中。运行以下命令初始化新的验证者:

#Configuring Node 7
mkdir -p qdata/node7/geth
cp static-nodes.json qdata/node7
cp enode_id_5 qdata/node7/geth/nodekey
./geth --datadir qdata/node7 init genesis.json
• 1
• 2
• 3
• 4
• 5

现在,在上述命令成功运行后,是时候让 (2F+ 1) 其他验证者同意插入新的验证者了。为此,在所有其他验证者中运行以下命令:

istanbul.propose("0x349ec6eefe8453a875c4905f5581ea792806a3e5", true)
• 1

将第一个参数替换为您获得的新验证节点地址。现在,使用以下命令启动新的验证节点:

./geth --datadir qdata/node7 --mine --port 23006 --ipcpath "./geth.ipc" --istanbul.requesttimeout 5000 --istanbul.blockperiod 1 --istanbul.blockpausetime 20 console
• 1

现在,您可以运行 istanbul.getValidators() 来检查网络中所有验证者的列表。现在应该有五个。让我们从网络中移除一个验证者。假设我们想要移除第一个验证者。在第一个验证者的控制台中运行 eth.coinbase 找到其唯一地址。然后,在 (2F + 1) 个验证者中运行以下命令以从网络中移除第一个验证者:

istanbul.propose("0x05a6245732c2350ba2ed64e840394c2239f8ad1f", false)
• 1
• 2

在此处,使用您生成的第一个验证节点的地址替换第一个参数。

在移除或添加验证节点时,如果某个验证节点宕机,那么一旦它重新运行起来,它将自动了解到这些更改。

概要

在本章中,我们从以太坊区块链的基础知识开始,然后深入探讨了 Quorum 的特性和共识协议。然后,通过设置星座、Raft 和 IBFT 网络,我们第一次实践了 Quorum。现在,您应该对设置网络的过程感到满意了。下一步是学习编写智能合约,并部署我们的第一个智能合约。我们将在下一章中实现这一点。

第三章:编写智能合约

在上一章中,我们了解了 Quorum 的工作原理以及各种共识协议是如何保护它的。现在我们了解了 Quorum 的工作原理,让我们继续编写智能合约。Quorum 智能合约可以使用许多语言编写;最流行的是Solidity。在本章中,我们将学习 Solidity,并构建一个企业可以用来数字签署文件的 DApp。

在本章中,我们将涵盖以下主题:

  • Solidity 源文件的布局
  • 理解 Solidity 数据类型
  • 特殊变量和合约函数
  • 控制结构
  • 合约的结构和特性
  • 编译和部署合约

本章与作者之前的书籍项目区块链中的章节相同。这不是第二版的书籍,它被用来向读者解释基本概念。

Solidity 源文件

Solidity 源文件的识别方法是通过 .sol 扩展名。它有各种版本,就像通常的编程语言一样。在撰写本书时,最新版本是 0.4.17

在源文件中,您可以使用 pragma Solidity 指令来指定编写代码的编译器版本。例如:

pragma Solidity ⁰.4.17;
• 1

需要注意的是,源文件不会在早于 0.4.17 或晚于 0.5.0(此第二个条件使用 ^ 添加)的编译器版本下编译。编译器版本在 0.4.170.5.0 之间的情况最有可能包含 bug 修复,并且不太可能破坏任何内容。

我们可以为编译器版本指定更复杂的规则;表达式遵循 npm 使用的规则。

智能合约的结构

A 类似于一个类。它可以有函数、修改器、状态变量、事件、结构体和枚举。合约也支持继承。您可以通过在编译时复制代码来实现继承。智能合约也可以是多态的。

以下是一个智能合约的示例:

contract Sample
{
     //state variables 
     uint256 data;
     address owner;
     //event definition
     event logData(uint256 dataToLog);
     //function modifier
     modifier onlyOwner() {
         if (msg.sender != owner) throw;
         _; 
    }
     //constructor
     function Sample(uint256 initData, address initOwner){
         data = initData;
         owner = initOwner;
     }
     //functions
     function getData() returns (uint256 returnedData){
         return data;
     }
     function setData(uint256 newData) onlyOwner{
         logData(newData);
         data = newData;
     }
}
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19
• 20
• 21
• 22
• 23
• 24
• 25
• 26
• 27
• 28
• 29
• 30

让我们看看上述代码如何工作:

  • 首先,我们使用 contract 关键字声明了一个合约。
  • 接下来,我们声明了两个状态变量:data 保存一些数据;owner 保存了他们的以太坊钱包的地址,也就是合约部署的地址。状态变量构成智能合约的状态,并存储在智能合约的存储中。智能合约的存储位于数据库中。
  • 然后,我们定义了事件。事件用于客户端通知。我们的事件将在数据更改时触发。所有事件都保留在区块链中。
  • 接下来,我们定义了一个修改器函数。修改器在执行函数之前自动检查条件。我们的修改器检查合约所有者是否是调用函数的人。如果不是,则会抛出异常。
  • 在此之后,我们有了合约构造函数。它在部署合约时调用。构造函数用于初始化状态变量。
  • 最后,我们定义了两种方法。第一种方法获取数据状态变量的值,第二种方法更改数据值。

在更深入研究智能合约功能之前,我们必须学习与 Solidity 相关的一些重要事项。之后,我们将回到合约。

Solidity 中的数据位置

与其他编程语言不同,Solidity 的变量根据上下文存储在内存和数据库中。

总是有一个默认位置,但可以通过附加 storage 或 memory 来覆盖复杂类型的数据,例如字符串、数组和结构体。Memory 是函数参数(包括 return 参数)的默认值,而 storage 适用于局部和状态变量(显然)。

数据位置很重要,因为它们会改变赋值的行为:

  • 在存储变量和内存变量之间的赋值中,始终会创建独立的副本。但是,从一个内存存储的复杂类型赋值给另一个内存存储的复杂类型时,不会创建副本。
  • 对状态变量进行赋值时,始终会创建独立的副本(即使来自其他状态变量)。
  • 存储在内存中的复杂类型不能赋值给局部存储变量。
  • 如果状态变量赋给局部存储变量,那么局部存储变量将指向状态变量;基本上,局部存储变量充当指针。

不同类型的数据

Solidity 是一种静态类型语言;变量持有的数据类型需要预定义。所有变量的位默认都被赋值为零。在 Solidity 中,变量是在函数范围内生效;也就是说,无论在函数的任何地方声明的变量都将在整个函数范围内生效。

Solidity 提供了以下数据类型:

  • 最简单的数据类型是 bool。它可以存储 truefalse
  • uint8uint16uint24,一直到 uint256 用于存储 8 位、16 位、24 位,一直到 256 位的无符号整数。同样地,int8int16 一直到 int256 用于存储 8 位、16 位,一直到 256 位的有符号整数。uintintuint256int256 的别名。ufixedfixed代表分数。ufixed0x8ufixed0x16,一直到 ufixed0x256 用于存储 8 位、16 位,一直到 256 位的无符号分数。类似地,fixed0x8fixed0x16,一直到 fixed0x256 用于存储 8 位、16 位,一直到 256 位的有符号分数。如果我们有一个需要超过 256 位的数字,那么将使用 256 位数据类型,此时将存储数字的近似值。
  • 地址(Address)用于存储最多 20 字节的值,通过分配十六进制字面量。它用于存储以太坊地址。您可以在 Solidity 中使用 0x 前缀,将十六进制编码的值赋给变量。

数组

Solidity 支持通用和字节数组,固定大小和动态数组,以及多维数组。

bytes1bytes2bytes3,一直到 bytes32 都是字节数组的类型。我们将使用字节表示 bytes1

这是一些通用数组语法的示例:

contract sample{
//dynamic size array
//wherever an array literal is seen a new array is created. If the //array literal is in state, then it's stored in storage and if it's //found inside function, then its stored in memory
//Here myArray stores [0, 0] array. The type of [0, 0] is decided based //on its values.
//Therefore, you cannot assign an empty array literal.
     int[] myArray = [0, 0];
    function sample(uint index, int value){
         //index of an array should be uint256 type
         myArray[index] = value;
         //myArray2 holds pointer to myArray
         int[] myArray2 = myArray;
//a fixed size array in memory
//here we are forced to use uint24 because 99999 is the max value and //24 bits is the max size required to hold it.
//This restriction is applied to literals in memory because memory is //expensive. As [1, 2, 99999] is of type uint24, myArray3 also has to //be the same type to store pointer to it.
         uint24[3] memory myArray3 = [1, 2, 99999]; //array literal
//throws exception while compiling as myArray4 cannot be assigned to //complex type stored in memory
         uint8[2] myArray4 = [1, 2];
     }
}
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19
• 20
• 21
• 22

以下是您应该了解的一些关于数组的重要事项:

  • 数组还具有 length 属性,可用于查找数组的长度。还可以将 value 分配给 length 属性以更改数组大小。但是,内存中的数组或非动态数组无法调整大小。
  • 如果尝试访问动态数组的未设置的 index,则会引发异常。

字符串

在 Solidity 中,可以通过两种方式创建字符串:使用 bytesstringbytes 用于创建原始字符串,而 string 用于创建 UTF-8 字符串。字符串的长度始终是动态的。

以下是显示 string 语法的示例:

contract sample {
//wherever a string literal is seen, a new string is created. If the //string literal is in state, then it's stored in storage and if it's //found inside function, then its stored in memory
     //Here myString stores "" string.
     string myString = ""; //string literal
     bytes myRawString;
     function sample(string initString, bytes rawStringInit){
         myString = initString;
         //myString2 holds a pointer to myString
         string myString2 = myString;
         //myString3 is a string in memory
         string memory myString3 = "ABCDE";
         //here the length and content changes
         myString3 = "XYZ";
         myRawString = rawStringInit;
         //incrementing the length of myRawString
         myRawString.length++;
         //throws exception while compiling
         string myString4 = "Example";
         //throws exception while compiling
         string myString5 = initString;
    }
}
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19
• 20
• 21
• 22
• 23
• 24
• 25
• 26
• 27
• 28
• 29

结构体

Solidity 结构体。以下是 struct 语法的示例:

contract sample{
     struct myStruct {
         bool myBool;
         string myString;
     }
     myStruct s1;
    //wherever a struct method is seen, a new struct is created. If 
    //the struct method is in state, then it's stored in storage
    //and if it's found inside function, then its stored in memory
     myStruct s2 = myStruct(true, ""); //struct method syntax
     function sample(bool initBool, string initString){
         //create an instance of struct
         s1 = myStruct(initBool, initString);
        //myStruct(initBool, initString) creates an instance in memory
         myStruct memory s3 = myStruct(initBool, initString);
     }
}
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19
• 20
• 21

枚举

Solidity 枚举。以下是 enum 语法的示例:

contract sample {
     //The integer type which can hold all enum values and is the
     //smallest is chosen to hold enum values
     enum OS { Windows, Linux, OSX, UNIX }
     OS choice;
     function sample(OS chosen){
         choice = chosen;
     }
     function setLinuxOS(){
         choice = OS.Linux;
     }
     function getChoice() returns (OS chosenOS){
         return choice;
     } 
}
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19

映射

哈希表 是一种映射数据类型。由于映射只能存在于存储中,因此它们被声明为状态变量。您可以将映射看作具有 keyvalue 对的数据结构。key 实际上不会被存储;相反,将 keykeccak256 哈希用于查找 value。映射没有长度,并且无法分配给另一个映射。

以下是创建和使用 mapping 的示例:

contract sample{
     mapping (int => string) myMap;
     function sample(int key, string value){
         myMap[key] = value;
         //myMap2 is a reference to myMap
         mapping (int => string) myMap2 = myMap;
     }
}
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10

delete 运算符

delete 运算符可以应用于任何变量以将其重置为其默认值。默认值是所有位都分配为零。

如果我们对动态数组应用 delete,它将删除所有元素并使长度变为零。如果我们对静态数组应用 delete,它的所有索引都会被重置。我们也可以对特定的索引应用 delete,以重置它们。

然而,如果您将 delete 应用于映射类型,则不会发生任何事情。但是,如果您将 delete 应用于映射的 key,则与 key 关联的值将被删除。

让我们看看 delete 运算符的工作原理,如下所示:

contract sample { 
    struct Struct { 
        mapping (int => int) myMap; 
        int myNumber; 
    } 
    int[] myArray; 
    Struct myStruct; 
    function sample(int key, int value, int number, int[] array) { 
        //maps cannot be assigned so while constructing struct we
        // ignore the maps 
        myStruct = Struct(number); 
        //here set the map key/value 
        myStruct.myMap[key] = value; 
        myArray = array; 
    } 
    function reset(){ 
        //myArray length is now 0 
        delete myArray; 
        //myNumber is now 0 and myMap remains as it is 
        delete myStruct; 
    } 
    function deleteKey(int key){ 
        //here we are deleting the key 
        delete myStruct.myMap[key]; 
    } 
} 
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19
• 20
• 21
• 22
• 23
• 24
• 25
• 26
• 27
• 28
• 29
• 30
• 31
• 32
• 33
• 34
• 35
• 36
• 37
• 38

目录
相关文章
|
4月前
|
存储 算法 API
面向企业的区块链教程(一)(2)
面向企业的区块链教程(一)
88 6
|
区块链
区块链金融模式DeFI游戏开发搭建部署源码示例
# 定义代币合约 token_contract = Web3.toChecksumAddress('0xYourTokenContractAddress') # 获取代币合约对象 token_contract_instance = w3.eth.contract(address=token_contract, abi=YourTokenABI)
|
供应链 物联网 新制造
BC:带你温习并解读《中国区块链技术和应用发展白皮书》—区块链典型应用场景
BC:带你温习并解读《中国区块链技术和应用发展白皮书》—区块链典型应用场景
BC:带你温习并解读《中国区块链技术和应用发展白皮书》—区块链典型应用场景
|
存储 供应链 安全
BC:带你温习并解读《中国区块链技术和应用发展白皮书》—概述
BC:带你温习并解读《中国区块链技术和应用发展白皮书》—概述
BC:带你温习并解读《中国区块链技术和应用发展白皮书》—概述
BC:带你温习并解读《腾讯区块链方案白皮书》—区块链的兴起和未来之路
BC:带你温习并解读《腾讯区块链方案白皮书》—区块链的兴起和未来之路
|
存储 传感器 人工智能
区块链参考论文集【九】
区块链作为一种崭新的、颠覆性的技术,是国内外活跃的研究领域和毕业设计选题方向。本文列出最新的一组区块链方面的论文,希望可以对选择区块链毕业设计的同学们有所帮助,这是汇智网编辑整理的区块链毕业设计论文系列中的第9篇。
1467 0
|
分布式计算 资源调度 安全
5月7日云栖精选夜读丨如何用阿里云快速构建游戏发行技术体系
在2018云栖大会深圳峰会阿里云支持与服务专场上,由卓游技术总监张保峰带来了“如何用阿里云快速构建游戏发行技术体系”的主题分享,主要从三方面进行讲解,首先介绍了选择和阿里云合作的背景与需求,其次对如何在阿里云的基础上做到快速构建游戏发行技术,最后总结了阿里云带来的优势。
3457 0
5月7日云栖精选夜读丨如何用阿里云快速构建游戏发行技术体系
|
人工智能 物联网 区块链
干货!区块链入门、进阶、行业专家观点!1000篇好文帮你破解区块链密码!(中篇)
互联网时代已经深入整个世界,区块链问世时,人们感受到的是另一个全新时代脚步正在靠近,春节期间引发社区热点的“三点钟无眠区块链”给了2018年开场红,区块链正要迎来它的新元年。云栖社区特整理出1000篇关于区块链的文章分享给大家,从技术原理到应用实践,应有尽有。
干货!区块链入门、进阶、行业专家观点!1000篇好文帮你破解区块链密码!(中篇)
|
存储 小程序 物联网
开放下载!《阿里云存储白皮书》全面解读阿里云存储二十年的技术演进 | 开发者必读(175期)
藏经阁又有哪些新书上架呢?《阿里云存储白皮书》《无需从0开发 平头哥教你1天上手蓝牙Mesh应用解决方案》《深入浅出玩转物联网平台》任你pick~还有精彩新书发布会,快来围观
1747 0