相关工具
Solidity:https://github.com/ethereum/solidity
Web3.js:https://github.com/ethereum/web3.js
Geth:https://github.com/ethereum/go-ethereum
Mist:https://github.com/ethereum/mist
Remix:https://remix.ethereum.org/
Solidity是以太坊开发智能合约的高级语言,采用面向对象的开发方式,有一套自己的语法体系,是图灵完备的。
Web3.js是基于javascript的调用智能合约的类库。之前还可以编译和部署智能合约,不过现在已经废除了,暂时还没有找到更好的替代方式,本文是采用mist客户端进行编译和部署的,然后再通过web3.js进行调用。
Geth是以太坊客户端,可以用来挖矿,也可以搭建私有的以太坊环境。
Mist是以太坊的钱包工具,可以进行转账交易和智能合约的开发。
Remix是Solidity语言的基于Web的IDE,代码编写以及错误调试非常方便,一般在Remix调试没有问题之后,在通过Mist进行发布。另外,在没有搭建私链的环境是,可以结合chrom的浏览器扩展metamask,在测试链上进行开发。
私链环境搭建
Geth搭建以太坊私链环境:http://blog.csdn.net/koastal/article/details/78737543
搭建以太坊私有链多节点环境:http://blog.csdn.net/koastal/article/details/78749211
智能合约
- 利用
struct
存储用户的属性,这里只写了姓名和年龄。 - 利用
mapping
存储uid
与struct
的映射关系。 - 利用
array
存储uid
,也就是作为“数据库的索引”。 - 插入操作成功之后,用户获得一个自增的
uid
,也就是IdList
中的最大值+1的结果。 - 更新和删除都是通过
uid
找到该用户记录,然后操作。 - 插入、更新和删除都属于写操作,需要调用者支付费用(Gas)。
- 写操作都定义了相关的事件,在操作成功之后调用事件。
pragma solidity ^0.4.6;
contract UserCurd {
struct UserStruct {
string name;
uint age;
}
mapping(uint => UserStruct) private UserStructs;
uint[] private IdList;
event InsertEvent(uint uid,string name,uint age);
event UpdateEvent(uint uid,string name,uint age);
event DeleteEvent(uint uid);
//插入操作
function insertUser(string name,uint age) public returns(uint uid){
uint length = IdList.length;
uint id;
if(length == 0){
id = 1;
}else{
uint lastId = IdList[length-1];
id = lastId+1;
}
IdList.push(id);
uid = IdList.length;
UserStructs[id].name = name;
UserStructs[id].age = age;
InsertEvent(uid,name,age); //插入成功,触发插入事件
return uid;
}
//查询操作
function getUser(uint uid) public view returns(uint retUid,string retName, uint retAge){
require(isExist(uid) > -1);
return (uid,UserStructs[uid].name,UserStructs[uid].age);
}
function getUidList() public view returns(uint[]){
return IdList;
}
function isExist(uint uid) public view returns(int){
if(IdList.length == 0) return -1;
for(uint i=0;i<IdList.length;i++){
if(IdList[i] == uid) return int(i);
}
return -1;
}
//更新操作
function updateUser(uint uid,string name,uint age) public returns(bool){
if(isExist(uid) < 0) return false;
UserStructs[uid].name = name;
UserStructs[uid].age = age;
UpdateEvent(uid,name,age); //更新成功,触发更新事件
return true;
}
//删除操作
function deleteUser(uint uid) public returns(bool){
int index = isExist(uid);
if(index < 0) return false;
delete UserStructs[uid];
for(uint i= uint(index);i<IdList.length-1;i++){
IdList[i] = IdList[i+1];
}
IdList.length--;
DeleteEvent(uid); //删除成功,触发更新事件
return true;
}
}
合约部署成功之后的mist界面
web3.js调用
调用智能合约需要知道合约的地址和ABI,如果进行写入操作的话,还需要一个有充足以太币的账户为写入操作进行付费。
let Web3 = require("web3");
let fs = require("fs");
let web3 = new Web3();
web3.setProvider(new Web3.providers.HttpProvider("http://192.168.1.11:8545"));
let address = "0x61C64CE900236575F2212D7346c12BE9d1e9002d";
let abi = JSON.parse(fs.readFileSync("./solidity/UserCurd.abi").toString("utf8"));
let MyContract = web3.eth.contract(abi);
let contractInstance = MyContract.at(address);
//查询用户
function listUser() {
let list = contractInstance.getUidList();
let uids = [];
for(let obj of list){
uids.push(obj.c[0]);
}
let userList = [];
for(let uid of uids){
let res = contractInstance.getUser(uid);
let name = res[1].replace(/"/g,'');
let age = res[2].c[0];
userList.push({
uid : uid,
name : name,
age : age
});
}
console.log("User List:");
console.log(userList);
}
//添加用户
function insertUser(name,age) {
name = name || "default";
age = age || 1;
let coinbase = "0x8a1C505f1ff14045c03622E9ab82EB19c730cef3";
web3.personal.unlockAccount(coinbase, "coinbase", 500);
contractInstance.insertUser(name,age, {from: coinbase, gas: 1000000});
let myEvent = contractInstance.InsertEvent();
myEvent.watch(function (err,result) {
if(err){
console.log("Insert Error:");
console.log(err);
}else{
console.log(result);
listUser();
}
})
}
//删除用户
function deleteUser(uid) {
uid = parseInt(uid);
if(uid <= 0) return false;
let coinbase = "0x8a1C505f1ff14045c03622E9ab82EB19c730cef3";
web3.personal.unlockAccount(coinbase, "coinbase", 500);
contractInstance.deleteUser(uid, {from: coinbase, gas: 1000000});
let myEvent = contractInstance.DeleteEvent();
myEvent.watch(function (err,result) {
if(err){
console.log("Delete Error:");
console.log(err);
}else{
console.log(result);
listUser();
}
})
}
//修改用户
function updateUser(uid,name,age) {
uid = parseInt(uid);
name = name || "default";
age = age || 1;
if(uid <= 0) return false;
let coinbase = "0x8a1C505f1ff14045c03622E9ab82EB19c730cef3";
web3.personal.unlockAccount(coinbase, "coinbase", 500);
contractInstance.updateUser(uid,name,age, {from: coinbase, gas: 1000000});
let myEvent = contractInstance.UpdateEvent();
myEvent.watch(function (err,result) {
if(err){
console.log("Update Error:");
console.log(err);
}else{
console.log(result);
listUser();
}
})
}
读取操作
因为是刚部署的合约,用户列表是空的
读取用户列表
listUser();
写入操作
首先需要在私链中开启挖矿,因为对智能合约的写入操作,也是一笔交易,需要有矿工挖矿打包才能完成。
minner.start()
插入用户
insertUser("one",101);
insertUser("two",12);
我们插入两个用户,就发生了两笔交易,在私链挖矿节点能够看到
并且在web3.js监听的event中,也可以获取交易的具体信息
{ address: '0x61c64ce900236575f2212d7346c12be9d1e9002d',
blockNumber: 6329,
transactionHash: '0xe01c9434fb832863e2c2cc402eafa38822628483a1d18a29f95648479042e6d6',
transactionIndex: 0,
blockHash: '0xb83ef6bd21c2d07ebf0e36cfa066b9350178d3a99f964f5fdc51b781fc9238ad',
logIndex: 0,
removed: false,
event: 'InsertEvent',
args:
{ uid: { [String: '1'] s: 1, e: 0, c: [Object] },
name: 'one',
age: { [String: '101'] s: 1, e: 2, c: [Object] }
}
}
更新用户
updateUser(1,"one",11);
删除用户
deleteUser(1);
项目的github地址:
https://github.com/qianshou/Solidity-CURD/tree/master
参考资料:
https://bitbucket.org/rhitchens2/soliditycrud
http://blog.csdn.net/ddffr/article/details/73771940