Skip to content

Commit dda7f16

Browse files
committed
finish scrypt pars
1 parent ef2fa8e commit dda7f16

File tree

2 files changed

+181
-0
lines changed

2 files changed

+181
-0
lines changed

i18n/zh-CN/docusaurus-plugin-content-docs/current/contract/scrypt-language/compile-time-constant.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,57 @@
22
sidebar_position: 6
33
---
44
# 编译时常量
5+
6+
介绍编译期常量 (Compile Time Constant) 的概念和使用方法。
7+
8+
编译时常量(CTC)是可以在编译时计算的值。编译时常量有四种类型:
9+
10+
- 字面量
11+
- 归纳变量
12+
- 用字面量初始化的合约的静态常量属性
13+
- 静态常量函数参数
14+
15+
有几种情况下只能使用编译时常量:
16+
17+
- 循环边界
18+
- 数组大小
19+
- 使用索引操作符写入数组元素
20+
- 声明为静态常量的函数参数,例如`reverseBytes(bytes b, static const int size)`中的`size``repeat(T e, static const int size)`
21+
22+
```c
23+
contract CTC {
24+
static const int N = 4;
25+
static const int LOOPCOUNT = 30;
26+
27+
// A 不是 CTC,因为右边是一个表达式,而不是字面量
28+
static const int A = 2 + 1;
29+
// B 不是 CTC,因为它不是静态的
30+
const int B;
31+
32+
// FC 是在函数参数中声明的 CTC
33+
// 它可以在这个函数内使用,包括在它之后的参数和返回类型
34+
function incArr(static const int FC, int[FC] x) : int[FC] {
35+
loop(FC): i {
36+
x[i] += i; // 归纳变量 CTC
37+
}
38+
return x;
39+
}
40+
41+
public function unlock(int y) {
42+
int[N] arr0 = [1, 2, 3, 4];
43+
// 使用 `N` 初始化函数 `incArr` 的 CTC 参数 `FC`
44+
int[N] arr1 = this.incArr(N, repeat(1, N));
45+
loop(N): i {
46+
require(arr0[i] == arr1[i]);
47+
}
48+
49+
int z = 0;
50+
loop (LOOPCOUNT) {
51+
if (z < y) z += 4;
52+
}
53+
require(y == 1);
54+
}
55+
}
56+
```
57+
58+
注意:顺序很重要:在声明函数参数时,不允许使用 `const static`,但在声明属性时允许。

i18n/zh-CN/docusaurus-plugin-content-docs/current/contract/scrypt-language/stateful-contracts.md

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,130 @@
22
sidebar_position: 7
33
---
44
# 有状态合约
5+
6+
sCrypt合约使用未花费交易输出(UTXO)模型:合约位于一个UTXO中,规定了UTXO中的比特币如何被花费。当一个UTXO被花费时(即成功调用sCrypt合约的公共函数时),合约会被终止。为了让合约保持状态并能够在携带可变状态的情况下被多次调用,需要遵循以下步骤。
7+
8+
## 状态修饰符
9+
10+
使用修饰符@state声明任何作为状态部分的属性。状态属性可以像常规属性一样使用。
11+
12+
```c
13+
contract Counter {
14+
@state
15+
int counter;
16+
17+
constructor(int counter) {
18+
this.counter = counter;
19+
}
20+
}
21+
```
22+
23+
## 更新状态
24+
25+
通过将状态存储在锁定脚本中,合约可以在链式交易中保持状态。在以下示例中,合约从state0变为state1,然后变为state2。交易1 tx1的输入花费了tx0中的UTXO,而tx2花费了tx1。
26+
27+
## 保持状态
28+
29+
当你准备将新状态传递到下一个UTXO时,只需调用内置函数`this.updateState()`,并传入两个参数:
30+
- `txPreimage`:当前花费交易的预镜像。它必须只有一个输出并包含新状态。
31+
- `amount`:该单一输出中的satoshi数量。
32+
33+
对于每个有状态合约(即,至少有一个用@state装饰的属性的合约),该函数会自动生成。如果需要自定义sighash类型(不同于默认的SigHash.ALL | SigHash.FORKID),可以使用`updateStateSigHashType`
34+
35+
以下是一个记录`increment()`调用次数的示例合约:
36+
37+
```c
38+
contract Counter {
39+
@state
40+
int counter;
41+
42+
public function increment(SigHashPreimage txPreimage, int amount) {
43+
// 改变状态
44+
this.counter++;
45+
46+
require(this.updateState(txPreimage, amount));
47+
48+
// 自定义sighash类型
49+
// require(this.updateStateSigHashType(txPreimage, amount, SigHash.SINGLE | SigHash.FORKID));
50+
}
51+
}
52+
```
53+
54+
## 进阶
55+
56+
如果你需要更细粒度地控制状态,例如在花费交易中有多个输出,可以调用另一个内置函数`this.getStateScript()`来获取包含最新状态属性的锁定脚本。
57+
58+
接下来,使用`OP_PUSH_TX`确保包含状态的输出进入当前花费交易。这相当于上述合约使用`this.updateState()`
59+
60+
```c
61+
contract Counter {
62+
@state
63+
int counter;
64+
65+
public function increment(SigHashPreimage txPreimage, int amount) {
66+
// 改变状态
67+
this.counter++;
68+
69+
require(Tx.checkPreimage(txPreimage));
70+
71+
// 获取包含最新状态属性的锁定脚本
72+
bytes outputScript = this.getStateScript();
73+
74+
// 从锁定脚本和satoshi数量构造一个输出
75+
bytes output = Utils.buildOutput(outputScript, amount);
76+
// 这里只使用一个输入
77+
require(hash256(output) == SigHash.hashOutputs(txPreimage));
78+
}
79+
}
80+
```
81+
82+
## 限制
83+
84+
对于任何公共函数访问有状态属性,必须包含一个通过`Tx.checkPreimage()`验证的SighashPreimage参数,即使用`OP_PUSH_TX`。这不适用于任何非公共函数,包括构造函数。
85+
86+
```c
87+
contract Counter {
88+
@state
89+
int counter;
90+
91+
constructor(int counter) {
92+
// 可以:非公共函数
93+
this.counter = counter;
94+
}
95+
96+
public function increment(SigHashPreimage txPreimage, int amount) {
97+
// 可以
98+
this.counter++;
99+
100+
require(Tx.checkPreimage(txPreimage));
101+
}
102+
103+
public function foo(SigHashPreimage txPreimage, int amount) {
104+
require(Tx.checkPreimageOpt(txPreimage));
105+
106+
// 可以
107+
this.counter++;
108+
109+
require(true);
110+
}
111+
112+
public function bar(SigHashPreimage txPreimage) {
113+
// 不可以:缺少Tx.checkPreimage*()
114+
this.counter++;
115+
116+
require(true);
117+
}
118+
119+
public function baz(int i) {
120+
// 不可以:缺少SigHashPreimage
121+
this.counter++;
122+
123+
require(true);
124+
}
125+
126+
function baz() : int {
127+
// 可以:非公共函数
128+
return this.counter;
129+
}
130+
}
131+
```

0 commit comments

Comments
 (0)