1. evm虚拟机
交易的执行是区块链节点上的一个重要的功能。是把交易中的智能合约二进制代码取出来,用执行器(Executor)执行。在交易的执行过程中,会对区块链的状态(State)进行修改,形成新区块的状态储存下来(Storage)。执行器在这个过程中,类似于一个黑盒,输入是智能合约代码,输出是状态的改变.
以太坊虚拟机(environment virtual machine,简称EVM),作用是将智能合约代码编译成可在以太坊上执行的机器码,并提供智能合约的运行环境。它是一个对外完全隔离的沙盒环境,在运行期间不能访问网络、文件,即使不同合约之间也有有限的访问权限。以太坊虚拟机提供了面向合约的高级编程语言solidity,这使得开发者可以专注于应用本身,更方便、快捷的开发去中心化应用程序,同时也大大降低了开发难度。
EVM是一种基于栈的虚拟机(区别于基于寄存器的虚拟机),用于执行智能合约,同时EVM是图灵完备的,EVM操作数栈调用深度为1024,EVM机器码长度一个字节,最多可以有256个操作码,目前已经定义了144个操作码,还有100多个操作码可以扩展,每个操作码都根据其弹栈数、压栈数定义了相应的gas消耗数量。泰岳链应用了以太坊EVM机制来实现智能合约,并增加了对国密算法的支持(SM3)。
2. solidity语言
Solidity 是一门面向合约的、为实现智能合约而创建的高级编程语言。这门语言受到了 C++,Python 和 Javascript 语言的影响,设计的目的是能在 以太坊虚拟机(EVM) 上运行。
Solidity 是静态类型语言,支持继承、库和复杂的用户定义类型等特性。
直接看这里:Solidity最新中文文档
3. 使用Ganache与truffle进行合约开发
Ganache
ganache可以快速的在本机上启动一条以太坊链,用户可以方便的在上面部署合约,调用合约,完成各种与合约之间的交互。
ganache提供了Windows、Linux以及Mac三种系统的版本,直接到其官网或GitHub页面下载安装即可。
安装完成后,即可以快速部署一条链
使用QUICKSTART
模式部署的链只会在本次会话中存在,关闭当前会话或注销当前用户都会导致链的撤销,如果只是写个小demo的话,那么使用这种方式即可。NEW WORKSPACE
则会创建一条持久化的链,不会因会话结束或用户注销而撤销链。
使用
QUICKSTART
模式启动
ganache会自动创建10个测试账号,每个账号分配了100个原生币,交易需要消耗这些原生币。
在页面的上方,还有其他一些选项卡,可以方便的查看当前区块、交易、事件、日志等。需要注意的是在这些选项卡的下方,还标注了本链的一些信息,如它的端口,网络ID等。
truffle
truffle
提供了合约开发、测试、部署等一系列工具,通过与Ganache
配合可以十分方便的测试你的合约。
安装truffle
npm install -g truffle
新建一个truffle
项目
mkdir MyContract
truffle init
truffle
会创建如下的目录结构:
├── contracts
│ └── Migrations.sol
├── migrations
│ └── 1_initial_migration.js
├── test
└── truffle-config.js
contract目录中存放我们的合约;migrations目录中存放migrate文件,功能类似数据库migrate文件,简单来说,就是让你的应用从一个状态迁移到另一个状态;test目录中存放测试文件(还未创建);truffle-config.js是配置文件,其中配置了链的地址等信息。
根据提示我们来创建一个简单的合约模板:
truffle create contract Counter
truffle
创建了Counter.sol
文件,再次查看目录结构:
├── contracts
│ ├── Counter.sol
│ └── Migrations.sol
├── migrations
│ └── 1_initial_migration.js
├── test
└── truffle-config.js
打开Counter.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
contract Counter {
constructor() public {
}
}
为我们提供了一个合约模板,修改合约:
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
contract counter {
address owner;
mapping (string => uint256) values;
constructor() public {
owner = msg.sender;
}
function increase(string memory key) public payable {
values[key] = values[key] + 1;
}
function get(string memory key) view public returns (uint) {
return values[key];
}
function getOwner()view public returns (address) {
return owner;
}
}
以上合约是一个非常简单的计数器合约,提供了increase, get, getOwner
三个方法,分别用来增加计数、获取计数值、获取合约所有者。
编译合约
truffle compile
编辑migrate文件
vim migrations/2_deploy_contracts.js
const Counter = artifacts.require("Counter")
module.exports = function(deployer) {
deployer.deploy(Counter);
}
现在准备工作已经完成了,开始让我们的合约上链。
配置truffle-config.js文件,主要是要配置network:
networks: {
development: {
host: "127.0.0.1", // Localhost (default: none)
port: 7545, // Standard Ethereum port (default: none)
network_id: "*", // Any network (default: none)
},
},
networks有很详细的注释,这里的关键是需要与Ganache
中显示的端口号等一致。
配置完成,终于到了激动人心的一步,合约上链。
truffle migrate
Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.
Starting migrations...
======================
> Network name: 'development'
> Network id: 5777
> Block gas limit: 6721975 (0x6691b7)
1_initial_migration.js
======================
Deploying 'Migrations'
----------------------
> transaction hash: 0x75050e06c2f6f1097257de17ea1370a86225c35909e8319ed62407424b21587e
> Blocks: 0 Seconds: 0
> contract address: 0xd366fCAF0F7A2b1A2Ebde67E89f1bbC2ED708c55
> block number: 112
> block timestamp: 1623909962
> account: 0x128F3853c98671ac43e8358e3A043f3A7bD0Ca18
> balance: 99.72713514
> gas used: 191943 (0x2edc7)
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.00383886 ETH
2_deploy_contracts.js
=====================
Deploying 'Counter'
-------------------
> transaction hash: 0x692c27b1b9a7f04301c10a2b3ece8c5f7737581d4de9f01e88653a907eb4b711
> Blocks: 0 Seconds: 0
> contract address: 0x76607048A6628A43d981811a35a629Ff049c2B11
> block number: 114
> block timestamp: 1623910129
> account: 0x128F3853c98671ac43e8358e3A043f3A7bD0Ca18
> balance: 99.72055518
> gas used: 286660 (0x45fc4)
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.0057332 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.0057332 ETH
Summary
=======
> Total deployments: 2
> Final cost: 0.00957206 ETH
从输出的日志信息中可以看到部署的合约及其消耗的资源。
查看Ganache
可看到,链增长了4个区块
消耗的原生币也显示了出来
执行的所有交易
现在我们完成了合约编写,合约上链等步骤,但到这里只能证明合约语法的正确性,我们还需要进行一系列的测试来保证我们的合约逻辑是无误的,可以按照我们预定的逻辑执行。
生成测试代码(可选)
truffle create test Counter
cat test/counter.js
const Counter = artifacts.require("Counter");
/*
* uncomment accounts to access the test accounts made available by the
* Ethereum client
* See docs: https://www.trufflesuite.com/docs/truffle/testing/writing-tests-in-javascript
*/
contract("Counter", function (/* accounts */) {
it("should assert true", async function () {
await Counter.deployed();
return assert.isTrue(true);
});
});
如果你不想自动生成代码,那么可以手动创建自己的测试文件
vim test/counter.test.js
内容同上
开始测试
$ truffle test
Using network 'development'.
Compiling your contracts...
===========================
> Compiling ./contracts/Counter.sol
> Artifacts written to /tmp/test--10676-pZQ9laXW37D3
> Compiled successfully using:
- solc: 0.5.16+commit.9c3226ce.Emscripten.clang
Contract: Counter
✓ should assert true
1 passing (74ms)
以上的测试文件中,断言永远为真,所以只要这个测试可以跑起来,就肯定不会fail,这只是官方给我们生成的测试代码模板,真正的测试代码还需要我们自己来编写。 修改测试代码:
const Counter = artifacts.require("Counter");
contract("counter", async account => {
contract("counter 1st test", async account => {
let c;
before("deploy contract", async () => {
c = await Counter.deployed();
})
it("test getOwner", async () => {
const owner = await c.getOwner();
expectedOwner = "0x128F3853c98671ac43e8358e3A043f3A7bD0Ca18"
assert.equal(owner, expectedOwner, "owner is wrong")
})
it("test increase", async () => {
await c.increase("0x128F3853c98671ac43e8358e3A043f3A7bD0Ca18")
const num = await c.get("0x128F3853c98671ac43e8358e3A043f3A7bD0Ca18")
let expectedNum = 1;
assert.equal(expectedNum, num, "error occur");
})
})
});
重新运行测试:
truffle test
Using network 'development'.
Compiling your contracts...
===========================
> Compiling ./contracts/Counter.sol
> Artifacts written to /tmp/test--10825-NWIGDIdS1RrG
> Compiled successfully using:
- solc: 0.5.16+commit.9c3226ce.Emscripten.clang
Contract: counter
Contract: counter 1st test
✓ test getOwner
✓ test increase (81ms)
2 passing (184ms)
测试通过,完美。
更多资料,请参考官网文档:TRUFFLE SUITE
时间处理: https://ethereum.stackexchange.com/questions/34110/compare-dates-in-solidity