区块链技术-智能合约Solidity编程语言

 

在线wirte&debug Solidity   

http://remix.ethereum.org/

 

如何编写一个可升级的智能合约

 

solidity 基础

http://www.tryblockchain.org/

 

https://www.jianshu.com/p/8794afea1996

 

前置工作:

1. 创建工程目录

在你想放工程的任何位置,创建一个文件夹truffleTest,来做为你的工程根目录。

$ mkdir -p /Users/admin/develop/blockchain_workspace/truffleTest

2. 初始化框架

进入到工程根目录下(现在应该是个空目录),并执行下述命令。

$ cd /Users/admin/develop/blockchain_workspace/truffleTest
$ truffle init

正确执行后,我们将得到下面这样的目录结构:

 

目录结构简单说明如下:

  • app/ - 你的应用文件运行的默认目录。这里面包括推荐的javascript文件和css样式文件目录,但你可以完全决定如何使用这些目录。
  • contract/ - Truffle默认的合约文件存放地址。
  • migrations/ - 存放发布脚本文件
  • test/ - 用来测试应用和合约的测试文件
  • truffle.js - Truffle的配置文件
 
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
appledeiMac:blockchain_workspace youhui$ ls
bin         migrations      truffle.js
build           test
contracts       truffle-config.js
appledeiMac:blockchain_workspace youhui$ truffle compile
appledeiMac:blockchain_workspace youhui$ truffle develop
Truffle Develop started at http://localhost:9545/
 
Accounts:
(0) 0x627306090abab3a6e1400e9345bc60c78a8bef57
(1) 0xf17f52151ebef6c7334fad080c5704d77216b732
(2) 0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef
(3) 0x821aea9a577a9b44299b9c15c88cf3087f3b5544
(4) 0x0d1d4e623d10f9fba5db95830f7d3839406c6af2
(5) 0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e
(6) 0x2191ef87e392377ec08e7c08eb105ef5448eced5
(7) 0x0f4f2ac550a1b4e2280d04c21cea7ebd822934b5
(8) 0x6330a553fc93768f612722bb8c2ec78ac90b3bbc
(9) 0x5aeda56215b167893e80b4fe645ba6d5bab767de
 
Private Keys:
(0) c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3
(1) ae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f
(2) 0dbbe8e4ae425a6d2687f1a7e3ba17bc98c673636790f1b8ad91193c05875ef1
(3) c88b703fb08cbea894b6aeff5a544fb92e78a18e19814cd85da83b71f772aa6c
(4) 388c684f0ba1ef5017716adb5d21a053ea8e90277d0868337519f97bede61418
(5) 659cbb0e2411a44db63778987b1e22153c086a95eb6b18bdf89de078917abc63
(6) 82d052c865f5763aad42add438569276c00d3d88a2d062d36b2bae914d58b8c8
(7) aa3680d5d48a8283413f7a108367c7299ca73f553735860a87b08f39395618b7
(8) 0f62d96d6675f32685bbdb8ac13cda7c23436f63efbb9d07700d8669ff12b7c4
(9) 8d5366123cb560bb606379f90a0bfd4769eecc0557f1b362dcae9012b548b1e5
 
Mnemonic: candy maple cake sugar pudding cream honey rich smooth crumble sweet treat
 
truffle(develop)> migrate --reset
Using network 'develop'.
 
Running migration: 1_initial_migration.js
  Replacing Migrations...
  ... 0x5a954b2101a2126c3ebaddae75747854f2ee0f5cbc23db4be1f1a58606194c5c
  Migrations: 0x8cdaf0cd259887258bc13a92c0a6da92698644c0
Saving successful migration to network...
  ... 0xd7bc86d31bee32fa3988f1c1eabce403a1b5d570340a3a9cdba53a472ee8c956
Saving artifacts...
Running migration: 2_deploy_contracts.js
  Replacing Greeter...
  ... 0x00855600c7f16f4b4073c36cf4889cb856d969e21ea7674ed5eb18b1ebc950f0
  Greeter: 0x345ca3e014aaf5dca488057592ee47305d9b3e10
Saving successful migration to network...
  ... 0xf36163615f41ef7ed8f4a8f192149a0bf633fe1a2398ce001bf44c43dc7bdda0
Saving artifacts...
truffle(develop)> Greeter.deployed().then(function(instance){return instance.setGreeting("666");});
{ tx: '0x7e4335d9bf092d46adefe8cbf74357e74a71b919cc0435b52a00fd9a662598d2',
  receipt:
   { transactionHash: '0x7e4335d9bf092d46adefe8cbf74357e74a71b919cc0435b52a00fd9a662598d2',
     transactionIndex: 0,
     blockHash: '0x739930c891e058b81ac3e20fa66769a6c6e7117383752f7169edb2916b95dabd',
     blockNumber: 5,
     gasUsed: 42847,
     cumulativeGasUsed: 42847,
     contractAddress: null,
     logs: [],
     status: '0x01',
     logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' },
  logs: [] }
truffle(develop)> Greeter.deployed().then(function(instance){return instance.greet.call();}).then(function(value){return value;});
'666'
truffle(develop)>

  

 

 

Greeter.deployed().then(i=>i.setGreeting("hello world"))

 

 

Greeter.deployed().then(i=>i.greet.call()).then(function(value){return value;});

 

 

 

 

 

 

 

Solidity API 主要表现为Solidity 内置的特殊的变量及函数,他们存在于全局命名空间里,主要分为以下几类:

  1. 有关区块和交易的属性
  2. 有关错误处理
  3. 有关数学及加密功能
  4. 地址相关
  5. 合约相关

下面详细讲解下

区块和交易的属性(Block And Transaction Properties)

用来提供一些区块链当前的信息。

  • block.blockhash(uint blockNumber) returns (bytes32):返回给定区块号的哈希值,只支持最近256个区块,且不包含当前区块。
  • block.coinbase (address): 当前块矿工的地址。
  • block.difficulty (uint):当前块的难度。
  • block.gaslimit (uint):当前块的gaslimit。
  • block.number (uint):当前区块的块号。
  • block.timestamp (uint): 当前块的Unix时间戳(从1970/1/1 00:00:00 UTC开始所经过的秒数)
  • msg.data (bytes): 完整的调用数据(calldata)。
  • msg.gas (uint): 当前还剩的gas。
  • msg.sender (address): 当前调用发起人的地址。
  • msg.sig (bytes4):调用数据(calldata)的前四个字节(例如为:函数标识符)。
  • msg.value (uint): 这个消息所附带的以太币,单位为wei。
  • now (uint): 当前块的时间戳(block.timestamp的别名)
  • tx.gasprice (uint) : 交易的gas价格。
  • tx.origin (address): 交易的发送者(全调用链)

注意:
msg的所有成员值,如msg.sender,msg.value的值可以因为每一次外部函数调用,或库函数调用发生变化(因为msg就是和调用相关的全局变量)。

不应该依据 block.timestamp, now 和 block.blockhash来产生一个随机数(除非你确实需要这样做),这几个值在一定程度上被矿工影响(比如在赌博合约里,不诚实的矿工可能会重试去选择一个对自己有利的hash)。

对于同一个链上连续的区块来说,当前区块的时间戳(timestamp)总是会大于上一个区块的时间戳。

为了可扩展性的原因,你只能查最近256个块,所有其它的将返回0.

错误处理

  • assert(bool condition)
    用于判断内部错误,条件不满足时抛出异常
  • require(bool condition):
    用于判断输入或外部组件错误,条件不满足时抛出异常
  • revert():
    终止执行并还原改变的状态

数学及加密功能

  • addmod(uint x, uint y, uint k) returns (uint):
    计算(x + y) % k,加法支持任意的精度且不会在2**256处溢出,从0.5.0版本开始断言k != 0。
  • mulmod(uint x, uint y, uint k) returns (uint):
    计算 (x * y) % k, 乘法支持任意的精度且不会在2**256处溢出, 从0.5.0版本开始断言k != 0。
  • keccak256(...) returns (bytes32):
    使用以太坊的(Keccak-256)计算HASH值。紧密打包参数。
  • sha256(...) returns (bytes32):
    使用SHA-256计算hash值,紧密打包参数。
  • sha3(...) returns (bytes32):
    keccak256的别名
  • ripemd160(...) returns (bytes20):
    使用RIPEMD-160计算HASH值。紧密打包参数。
  • ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address):
    通过椭圆曲线签名来恢复与公钥关联的地址,或者在错误时返回零。可用于签名数据的校验,如果返回结果是签名者的公匙地址,那么说明数据是正确的。

    ecrecover函数需要四个参数,需要被签名数据的哈希结果值,r,s,v分别来自签名结果串。
    r = signature[0:64]
    s = signature[64:128]
    v = signature[128:130]
    其中v取出来的值或者是00或01。要使用时,我们先要将其转为整型,再加上27,所以我们将得到27或28。在调用函数时v将填入27或28。

用javascript表达如下:

    var msg = '0x8CbaC5e4d803bE2A3A5cd3DbE7174504c6DD0c1C'

    var hash = web3.sha3(msg)
    var sig = web3.eth.sign(address, h).slice(2)
    var r = `0x${sig.slice(0, 64)}`
    var s = `0x${sig.slice(64, 128)}`
    var v = web3.toDecimal(sig.slice(128, 130)) + 27

订阅区块链技术专栏可以参考到完整的使用例子。

紧密打包参数(tightly packed)意思是说参数不会补位,是直接连接在一起的,下面几个是相等的。

keccak256("ab", "c")
keccak256("abc")

keccak256(0x616263)  // hex
keccak256(6382179)
keccak256(97, 98, 99)   //ascii

如果需要填充,可以使用显式类型转换:keccak256("\x00\x12") 与keccak256(uint16(0x12))相同。

注意,常量将使用存储它们所需的最少字节数来打包,例如keccak256(0) == keccak256(uint8(0))和keccak256(0x12345678) == keccak256(uint32(0x12345678))

在私链(private blockchain)上运行sha256,ripemd160或ecrecover可能会出现Out-Of-Gas报错。因为私链实现了一种预编译合约,合约要在收到第一个消息后才会真正存在(虽然他们的合约代码是硬编码的)。而向一个不存在的合约发送消息,所以才会导致Out-Of-Gas的问题。一种解决办法(workaround)是每个在你真正使用它们之前先发送1 wei到这些合约上来完成初始化。在官方和测试链上没有这个问题。

地址相关

  • .balance (uint256):
    Address的余额,以wei为单位。

  • .transfer(uint256 amount):
    发送给定数量的ether到某个地址,以wei为单位。失败时抛出异常。

  • .send(uint256 amount) returns (bool):
    发送给定数量的ether到某个地址,以wei为单位, 失败时返回false。

  • .call(...) returns (bool):
    发起底层的call调用。失败时返回false。

  • .callcode(...) returns (bool):
    发起底层的callcode调用,失败时返回false。
    不鼓励使用,未来可能会移除。

  • .delegatecall(...) returns (bool):
    发起底层的delegatecall调用,失败时返回false

更多信息参考地址篇

警告:send() 执行有一些风险:如果调用栈的深度超过1024或gas耗光,交易都会失败。因此,为了保证安全,必须检查send的返回值,如果交易失败,会回退以太币。如果用transfer会更好。

 

合约相关

  • this(当前合约的类型):
    表示当前合约,可以显式的转换为Address
  • selfdestruct(address recipient):
    销毁当前合约,并把它所有资金发送到给定的地址。
  • suicide(address recipient):
    selfdestruct的别名

另外,当前合约里的所有函数均可支持调用,包括当前函数本身。

 

 

 

posted on   youhui  阅读(2558)  评论(0编辑  收藏  举报

编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
< 2025年3月 >
23 24 25 26 27 28 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 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示