Skip to content
This repository was archived by the owner on Aug 27, 2025. It is now read-only.

Commit 7fde32b

Browse files
committed
More docs
1 parent 935d6b0 commit 7fde32b

File tree

5 files changed

+180
-139
lines changed

5 files changed

+180
-139
lines changed

README.md

Lines changed: 52 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1,182 +1,101 @@
1-
# Solidity Examples
2-
3-
## Standard library (draft)
1+
# Standard library (draft)
42

53
Temporary storage for a standard library of Solidity contracts.
64

75
This is a draft document.
86

9-
### Purpose
10-
11-
The standard library should provide Solidity libraries / functions for performing common tasks, such as working with strings, bits, and other common types, and for working with Ethereum and Ethereum related technologies, like for example Patricia Tries and RLP.
12-
13-
### Quality Assurance
14-
15-
Routines for making sure that code meets the required standards when it comes to:
16-
17-
1. Integrity
18-
2. Style
19-
3. Docs
20-
21-
#### Testing
22-
23-
npm test. Requires `solc` and `evm` (go ethereum) to be installed and added to $path. Test code is written in Solidity, and is executed directly in the evm.
24-
25-
#### Style
26-
27-
The standard library should serve as an (or perhaps *the*) example of strict, idiomatic Solidity. This means all code is written following the style guide, as well as the practices and patterns laid out at solidity.readthedocs.org. It also means utilizing the language features and compiler to the greatest extent possible. This way of working would not just be a way to ensure quality and readability, but also help drive the development of the style, practices and patterns themselves.
28-
29-
#### Documentation
30-
31-
Briefly: the documentation should specify - in a very clear and concise a way - what the contract of the library/function is, the interfaces / function signatures should reflect that, and the functions should (obviously) behave as described.
32-
33-
#### Manual review
34-
35-
Code should be reviewed by at least one person other then the writer.
36-
37-
#### Issues and feedback
38-
39-
Github issues and gitter solidity channel.
40-
41-
### Ranking / categorization of contracts
42-
43-
The QA only really applies to code that is meant to be used in production, but the library will also include code that has not reached that level.
44-
45-
Node.js has a system of categorizing libraries, experimental, stable, deprecated, and so forth. This library should have something similar.
46-
47-
48-
### Test layout
49-
50-
Tests are functor-styled single-method contracts extending the `STLTest` contract and implementing its `testImpl` method.
7+
## TOC
518

52-
Tests are automatically compiled and run using a trivial test-runner written in javascript. It uses native `solc` and `evm` (go ethereum) to compile and execute the actual test code.
9+
- [Purpose](#purpose)
10+
- [Packages](#packages)
11+
- [Quality Assurance](#quality-assurance)
12+
- [Commandline tool](#commandline-tool)
5313

54-
Tests that fail will throw. This is ensured by always using Solidity's `assert` function for test conditions.
14+
## Purpose
5515

56-
1. One test function signature.
57-
2. One contract per test, one function per contract.
58-
3. Two possible results: throws or does not throw.
16+
The standard library should provide Solidity libraries / functions for performing common tasks, such as working with strings, bits, and other common types, and for working with Ethereum and Ethereum related technologies, like for example Patricia Tries.
5917

60-
##### Example
18+
## Packages
6119

62-
This is the `STLTest` contract; its `test` method is the basis for all tests.
20+
These are the different packages.
6321

64-
```
65-
contract STLTest {
22+
[bits](docs/packages/bits.md)
6623

67-
function test() public payable returns (bool ret) {
68-
ret = true;
69-
testImpl();
70-
}
24+
[bytes](docs/packages/bytes.md)
7125

72-
function testImpl() internal;
26+
[math](docs/packages/math.md)
7327

74-
}
75-
```
28+
[patricia_tree](docs/packages/patricia_tree.md)
7629

77-
The test for `Bits.bitXor(uint bitfield, uint8 index)` looks like this:
30+
[rlp](docs/packages/rlp.md)
7831

79-
```
80-
contract TestBitsBitXor is BitsTest {
81-
function testImpl() internal {
82-
for (uint8 i = 0; i < 12; i++) {
83-
assert(ONES.bitXor(ONES, i*20) == 0);
84-
assert(ONES.bitXor(ZERO, i*20) == 1);
85-
assert(ZERO.bitXor(ONES, i*20) == 1);
86-
assert(ZERO.bitXor(ZERO, i*20) == 0);
87-
}
88-
}
89-
}
90-
```
32+
[strings](docs/packages/strings.md)
9133

92-
It loops over the tested `uint`s and makes sure XOR works as expected.
34+
[token](docs/packages/tokens.md)
9335

94-
`BitsTest` is a simple (abstract) contract that extends `STLTest` and includes some constants and bindings that are useful for multiple tests throughout the suite (this pattern is used in most suites):
36+
[unsafe](docs/packages/unsafe.md)
9537

96-
```
97-
contract BitsTest is STLTest {
98-
using Bits for uint;
38+
## Quality Assurance
9939

100-
uint constant ZERO = uint(0);
101-
uint constant ONE = uint(1);
102-
uint constant ONES = uint(~0);
103-
}
104-
```
40+
The standard library has well-documented routines for making sure that code meets the required standards when it comes to:
10541

106-
#### Naming
42+
1. Integrity
43+
2. Performance
44+
3. Style
45+
4. Documentation
10746

108-
The xor test is named `TestBitsBitXor`:
47+
Additionally, the tools used to guarantee this should be simple and easy to replace when new and better alternatives are made available.
10948

110-
1. `Test` is because it is a test contract, to distinguish it from other artifacts in the output directory. Tests always start with `Test`.
111-
2. `Bits` is the name of the library contract being tested.
112-
3. `BitXor` is the name of the function being tested.
49+
### Testing
11350

114-
Tests that are expected to throw must have the word `Throws` somewhere in the name. There can be other things in there as well, like further description of the test.
51+
`npm test` - runs the contract test-suite, as well as the tests for the typescript code.
11552

116-
All test contracts for a given library is normally kept in the same solidity source file.
53+
`npm ts-test` - runs the typescript tests.
11754

118-
#### Success and failure
55+
`npm contracts-test` - runs the contract test-suite.
11956

120-
In `STLTest.test()`, the test result is set to `true` prior to the execution of the actual test-code. This is done to detect if the function `throws` (although the `evm` also indicates that an illegal jump was made). The real point of this mechanism is to have uniformity over all tests (and a very simple way to interpret the return data in JS), which makes it easy to update.
57+
The contract tests requires `solc` and `evm` ([go ethereum](https://github.com/ethereum/go-ethereum)) to be installed and added to the $PATH. Test code is written in Solidity, and is executed directly in the evm.
12158

122-
1. If a test functor does not have the word `Throws` in the name, test passes if the return value is `true`.
123-
2. If a test functor has the word `Throws` in the name, test passes if the return value is not `true`.
59+
For more information about the tests, such as the test file format, read the full [test documentation](./docs/testing.md).
12460

125-
Note that the example test does not have the word `Throws` in the name, and is thus expected to not throw (i.e. none of the assertions is allowed to fail).
61+
For running tests with the command-line tool, check the [CLI documentation](./docs/cli.md).
12662

127-
## Perf
63+
### Performance
12864

129-
The performance of a contract is measured by looking at its gas-usage. It is mostly used in a relative way, by comparing the gas cost before and after code (or the compiler, or the evm) has been changed.
65+
`npm contracts-perf` will
13066

131-
The perf system is similar to the tests in that each perf is a single-method contract which is run in the go-ethereum `evm`, but unlike tests, perf functors implements the `perf`-function directly.
67+
For more information about the tests, such as the test file format, read the full [test documentation](./docs/testing.md).
13268

133-
The `perf` function returns the gas spent during execution of the tested function. This is implemented by storing the remaining gas before and after the function is executed, and then taking the difference.
69+
For running perf with the command-line tool, check the [CLI documentation](./docs/cli.md).
13470

135-
The reason that perf metering is done manually in every function is so that the implementor can exclude the staging part of the code (preparing variables & data) from the code that should be metered.
71+
### Style
13672

137-
#### Example
73+
`npm ts-lint` - will run TS-lint on the entire library.
13874

139-
This is the `STLPerf` contract; its `perf` method is the basis for all perf:
75+
`npm contracts-lint` - will run [solhint](https://github.com/protofire/solhint) on all contracts.
14076

141-
```
142-
contract STLPerf {
143-
function perf() public payable returns (uint);
144-
}
145-
```
77+
The standard library should serve as an (or perhaps *the*) example of strict, idiomatic Solidity. This means all code should follow the style guide and the practices and patterns laid out at https://solidity.readthedocs.org.
14678

147-
This is an example of a perf functor. It measures the gas cost when the `Bytes.equals` function can early out because the lengths of the two `bytes` are not the same:
79+
### Documentation
14880

149-
```
150-
contract PerfBytesEqualsDifferentLengthFail is BytesPerf {
151-
function perf() public payable returns (uint) {
152-
bytes memory bts1 = new bytes(0);
153-
bytes memory bts2 = new bytes(1);
154-
uint gasPre = msg.gas;
155-
Bytes.equals(bts1, bts2);
156-
uint gasPost = msg.gas;
157-
return gasPre - gasPost;
158-
}
159-
}
160-
```
81+
Briefly: the documentation should specify - in a very clear and concise a way - what the contract of the library/function is, the interfaces / function signatures should reflect that, and the functions should (obviously) behave as described.
16182

162-
## Packages
83+
### Manual review
16384

164-
These are the different packages.
85+
Code should be reviewed by at least one person other then the writer. There should also be review of tests, perf, docs, and code examples as well.
16586

166-
[bits](docs/packages/bits.md)
167-
168-
[bytes](docs/packages/bytes.md)
87+
This should be done using the PR system in github.
16988

170-
[math](docs/packages/math.md)
89+
### Issues and feedback
17190

172-
[patricia_tree](docs/packages/patricia_tree.md)
91+
Github issues and gitter solidity channel.
17392

174-
[rlp](docs/packages/rlp.md)
93+
### Ranking / categorization of contracts
17594

176-
[strings](docs/packages/strings.md)
95+
The QA only really applies to code that is meant to be used in production, but the library will also include code that has not reached that level.
17796

178-
[token](docs/packages/tokens.md)
97+
Node.js has a system of categorizing libraries, experimental, stable, deprecated, and so forth. This library should have something similar.
17998

180-
[unsafe](docs/packages/unsafe.md)
99+
## Commandline tool
181100

182-
On top of the package documentation there are also documentation in the contracts themselves, and a number of code examples in the `examples` folder.
101+
The library has a commandline tool which can be used to run tests, view documentation, and other things. The full docs can be found in the [commandline tool documentation](./docs/cli.md).

docs/cli.md

Whitespace-only changes.

docs/perf.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
## Perf
2+
3+
The performance of a contract is measured by looking at its gas-usage. It is mostly used in a relative way, by comparing the gas cost before and after code (or the compiler, or the evm) has been changed.
4+
5+
Each performance test is a single-method contract which is run in the go-ethereum `evm`, but unlike tests, perf functors implements the `perf`-function directly.
6+
7+
The `perf` function returns the gas spent during execution of the tested function. This is implemented by storing the remaining gas before and after the function is executed, and then taking the difference.
8+
9+
The reason that perf metering is done manually in every function is so that the implementor can exclude the staging part of the code (preparing variables & data) from the code that should be metered.
10+
11+
#### Example
12+
13+
This is the `STLPerf` contract; its `perf` method is the basis for all perf:
14+
15+
```
16+
contract STLPerf {
17+
function perf() public payable returns (uint);
18+
}
19+
```
20+
21+
This is an example of a perf functor. It measures the gas cost when the `Bytes.equals` function can early out because the lengths of the two `bytes` are not the same:
22+
23+
```
24+
contract PerfBytesEqualsDifferentLengthFail is BytesPerf {
25+
function perf() public payable returns (uint) {
26+
bytes memory bts1 = new bytes(0);
27+
bytes memory bts2 = new bytes(1);
28+
uint gasPre = msg.gas;
29+
Bytes.equals(bts1, bts2);
30+
uint gasPost = msg.gas;
31+
return gasPre - gasPost;
32+
}
33+
}
34+
```
35+
36+
### Absolute vs. relative results
37+
38+
Perf is not used primarily to check how much gas is spent when running a function; the main reason is to see how gas cost changes when there has been changes to the code, compiler, and runtime environment. This analysis is made possible by adding perf functions to all library functions, and using a system that computes and displays the difference if gas cost between code updates.
39+
40+
### Accuracy
41+
42+
The goal is to keep the perf result as close to the runtime gas-cost of the tested function as possible, but there will usually be a small difference. One reason is that part of the code may be optimized away unless some redundant code is added.
43+
44+
The goal is to minimize these deviations, but **there are no guaranteed bounds**.

docs/testing.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
## Tests
2+
3+
Tests are functor-styled single-method contracts extending the `STLTest` contract and implementing its `testImpl` method.
4+
5+
Tests are automatically compiled and run using a trivial test-runner written in javascript. It uses native `solc` and `evm` (go ethereum) to compile and execute the actual test code.
6+
7+
Tests that fail will throw. This is ensured by always using Solidity's `assert` function for test conditions.
8+
9+
1. One test function signature.
10+
2. One contract per test, one function per contract.
11+
3. Two possible results: throws or does not throw.
12+
13+
#### Example
14+
15+
This is the `STLTest` contract; its `test` method is the basis for all tests.
16+
17+
```
18+
contract STLTest {
19+
20+
function test() public payable returns (bool ret) {
21+
ret = true;
22+
testImpl();
23+
}
24+
25+
function testImpl() internal;
26+
27+
}
28+
```
29+
30+
The test for `Bits.bitXor(uint bitfield, uint8 index)` looks like this:
31+
32+
```
33+
contract TestBitsBitXor is BitsTest {
34+
function testImpl() internal {
35+
for (uint8 i = 0; i < 12; i++) {
36+
assert(ONES.bitXor(ONES, i*20) == 0);
37+
assert(ONES.bitXor(ZERO, i*20) == 1);
38+
assert(ZERO.bitXor(ONES, i*20) == 1);
39+
assert(ZERO.bitXor(ZERO, i*20) == 0);
40+
}
41+
}
42+
}
43+
```
44+
45+
It loops over the tested `uint`s and makes sure XOR works as expected.
46+
47+
`BitsTest` is a simple (abstract) contract that extends `STLTest` and includes some constants and bindings that are useful for multiple tests throughout the suite (this pattern is used in most suites):
48+
49+
```
50+
contract BitsTest is STLTest {
51+
using Bits for uint;
52+
53+
uint constant ZERO = uint(0);
54+
uint constant ONE = uint(1);
55+
uint constant ONES = uint(~0);
56+
}
57+
```
58+
59+
### Naming
60+
61+
The xor test is named `TestBitsBitXor`:
62+
63+
1. `Test` is because it is a test contract, to distinguish it from other artifacts in the output directory. Tests always start with `Test`.
64+
2. `Bits` is the name of the library contract being tested.
65+
3. `BitXor` is the name of the function being tested.
66+
67+
Tests that are expected to throw must have the word `Throws` somewhere in the name. There can be other things in there as well, like further description of the test.
68+
69+
All test contracts for a given library is normally kept in the same solidity source file.
70+
71+
### Success and failure
72+
73+
In `STLTest.test()`, the test result is set to `true` prior to the execution of the actual test-code. This is done to detect if the function `throws` (although the `evm` also indicates that an illegal jump was made). The real point of this mechanism is to have uniformity over all tests (and a very simple way to interpret the return data in JS), which makes it easy to update.
74+
75+
1. If a test functor does not have the word `Throws` in the name, test passes if the return value is `true`.
76+
2. If a test functor has the word `Throws` in the name, test passes if the return value is not `true`.
77+
78+
Note that the example test does not have the word `Throws` in the name, and is thus expected to not throw (i.e. none of the assertions is allowed to fail).

package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
},
88
"scripts": {
99
"test": "jest && node ./bin/main.js tests --silent",
10-
"js-lint": "tslint -p .",
11-
"js-test": "jest",
12-
"contract-lint": "solhint **/*.sol",
13-
"contract-compile": "node ./bin/main.js compile",
14-
"contract-tests": "node ./bin/main.js tests",
15-
"contract-perf": "node ./bin/main.js perf"
10+
"ts-lint": "tslint -p .",
11+
"ts-test": "jest",
12+
"contracts-lint": "solhint **/*.sol",
13+
"contracts-compile": "node ./bin/main.js compile",
14+
"contracts-test": "node ./bin/main.js tests",
15+
"contracts-perf": "node ./bin/main.js perf"
1616
},
1717
"repository": {
1818
"type": "git",

0 commit comments

Comments
 (0)