智能合约-CURD的详细分析

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
pragma solidity >=0.6.0 <0.7.0;

contract UserCrud {

// 业务主数据结构
struct UserStruct {
bytes32 userEmail;
uint userAge;
uint index;
}

// 将业务主数据存储在 mapping 中,用户地址是用户数据的索引
// address(key) ---> UserStruct
// 0x1 ---> userEmail:alice@co.com, userAge:22
// 0x2 ---> userEmail:bob@home.com, userAge:44
// 以上为 userStructs 中的存储内容
mapping(address => UserStruct) private userStructs;
// 用户地址被收集进入一个数组 userIndex
address[] private userIndex;
// 反馈新用户
event LogNewUser (address indexed userAddress, uint index, bytes32 userEmail, uint userAge);
// 反馈用户更新
event LogUpdateUser(address indexed userAddress, uint index, bytes32 userEmail, uint userAge);
// 反馈用户删除
event LogDeleteUser(address indexed userAddress, uint index);
// 判断入参的用户是否有与记录中的用户重合,即用户是否已经存在
function isUser(address userAddress)
public
view
returns(bool isIndeed)
{
if(userIndex.length == 0) return false;
return (userIndex[userStructs[userAddress].index] == userAddress);
}
// 插入新的用户主数据
function insertUser(
address userAddress,
bytes32 userEmail,
uint userAge)
public
returns(uint index)
{
if(isUser(userAddress)) {revert("this user already exist.");}
userStructs[userAddress].userEmail = userEmail;
userStructs[userAddress].userAge = userAge;
userIndex.push(userAddress);
userStructs[userAddress].index = userIndex.length-1;
emit LogNewUser(
userAddress,
userStructs[userAddress].index,
userEmail,
userAge);
return userIndex.length-1;
}
// 删除旧的用户主数据
function deleteUser(address userAddress)
public
returns(uint index)
{
if(!isUser(userAddress)) {revert("only other user can deleteUser.");}
uint rowToDelete = userStructs[userAddress].index;
address keyToMove = userIndex[userIndex.length-1];
userIndex[rowToDelete] = keyToMove;
userStructs[keyToMove].index = rowToDelete;
userIndex.pop();
emit LogDeleteUser(
userAddress,
rowToDelete);
emit LogUpdateUser(
keyToMove,
rowToDelete,
userStructs[keyToMove].userEmail,
userStructs[keyToMove].userAge);
return rowToDelete;
}
// 获取用户主数据
function getUser(address userAddress)
public
view
returns(bytes32 userEmail, uint userAge, uint index)
{
if(!isUser(userAddress)) {revert("only exist user can be run by getUser.");}
return(
userStructs[userAddress].userEmail,
userStructs[userAddress].userAge,
userStructs[userAddress].index);
}

function updateUserEmail(address userAddress, bytes32 userEmail)
public
returns(bool success)
{
if(!isUser(userAddress)) {revert("only exist user can updateUserEmail.");}
userStructs[userAddress].userEmail = userEmail;
emit LogUpdateUser(
userAddress,
userStructs[userAddress].index,
userEmail,
userStructs[userAddress].userAge);
return true;
}

function updateUserAge(address userAddress, uint userAge)
public
returns(bool success)
{
if(!isUser(userAddress)) {revert("only exist user can updateUserAge.");}
userStructs[userAddress].userAge = userAge;
emit LogUpdateUser(
userAddress,
userStructs[userAddress].index,
userStructs[userAddress].userEmail,
userAge);
return true;
}

function getUserCount()
public
view
returns(uint count)
{
return userIndex.length;
}

function getUserAtIndex(uint index)
public
view
returns(address userAddress)
{
return userIndex[index];
}

}

remix 调试如下图:

将上述模型进一步提炼为库文件

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
71
72
73
74
75
76
77
78
79
80
81
82
pragma solidity 0.5.1; 

/*
UnorderedKeySet v0.93
Library for managing CRUD operations in dynamic key sets.
https://github.com/rob-Hitchens/UnorderedKeySet
*/

library UnorderedKeySetLib {

struct Set {
mapping(bytes32 => uint) keyPointers;
bytes32[] keyList;
}

function insert(Set storage self, bytes32 key) internal {
require(key != 0x0, "UnorderedKeySet(100) - Key cannot be 0x0");
require(!exists(self, key), "UnorderedKeySet(101) - Key already exists in the set.");
self.keyPointers[key] = self.keyList.push(key)-1;
}

function remove(Set storage self, bytes32 key) internal {
require(exists(self, key), "UnorderedKeySet(102) - Key does not exist in the set.");
bytes32 keyToMove = self.keyList[count(self)-1];
uint rowToReplace = self.keyPointers[key];
self.keyPointers[keyToMove] = rowToReplace;
self.keyList[rowToReplace] = keyToMove;
delete self.keyPointers[key];
self.keyList.length--;
}

function count(Set storage self) internal view returns(uint) {
return(self.keyList.length);
}

function exists(Set storage self, bytes32 key) internal view returns(bool) {
if(self.keyList.length == 0) return false;
return self.keyList[self.keyPointers[key]] == key;
}

function keyAtIndex(Set storage self, uint index) internal view returns(bytes32) {
return self.keyList[index];
}

function nukeSet(Set storage self) public {
delete self.keyList;
}
}
// 合约只需要维护keyList即可
contract UnorderedKeySet {

using UnorderedKeySetLib for UnorderedKeySetLib.Set;
UnorderedKeySetLib.Set set;

event LogUpdate(address sender, string action, bytes32 key);

function exists(bytes32 key) public view returns(bool) {
return set.exists(key);
}

function insert(bytes32 key) public {
set.insert(key);
emit LogUpdate(msg.sender, "insert", key);
}

function remove(bytes32 key) public {
set.remove(key);
emit LogUpdate(msg.sender, "remove", key);
}

function count() public view returns(uint) {
return set.count();
}

function keyAtIndex(uint index) public view returns(bytes32) {
return set.keyAtIndex(index);
}

function nukeSet() public {
set.nukeSet();
}
}

另外 rob-Hitchens 使用 solidity 写了一个红黑树,地址如下:

https://github.com/rob-Hitchens/OrderStatisticsTree

有向图:

https://github.com/rob-Hitchens/GraphLib

关联文档:

  1. 智能合约-CURD的详细分析
  2. 智能合约-自毁模式
  3. 智能合约-工厂合约模式
  4. 智能合约-名字登录模式
  5. 智能合约-退款方式