Immutable¶
Welcome to the guide on creating immutable smart contracts! In this comprehensive resource, we will delve into the concept of immutability within blockchain technology and explore the crucial steps to design and deploy smart contracts that remain tamper-proof and unchangeable once executed. Immutability is a fundamental feature of blockchain systems, ensuring that data and code deployed on the blockchain cannot be altered or manipulated after deployment. Understanding how to leverage immutability effectively is essential for building secure and reliable decentralized applications (DApps).
Before embarking on this journey, ensure that you have already setup your Koinos AssemblyScript SDK environment by following this guide.
Setting up the project¶
Let's begin by creating a boilerplate smart contract project using the Koinos AssemblyScript SDK.
koinos-sdk-as-cli create immutable
Generating contract at "/home/$USER/Workspace/immutable" ...
Contract successfully generated!
You're all set! Run the following set of commands to verify that the generated contract is correctly setup:
cd /home/$USER/Workspace/immutable && yarn install && yarn build:debug && yarn test
Change your directory to the project directory and install dependencies.
cd immutable
yarn install
yarn install v1.22.22
info No lockfile found.
[1/4] Resolving packages...
warning @koinos/sdk-as > @koinos/mock-vm > multibase@4.0.6: This module has been superseded by the multiformats module
warning @koinos/sdk-as > @koinos/mock-vm > somap > npm > @npmcli/ci-detect@2.0.0: this package has been deprecated, use `ci-info` instead
warning @koinos/sdk-as > @koinos/mock-vm > somap > npm > libnpmexec > @npmcli/ci-detect@2.0.0: this package has been deprecated, use `ci-info` instead
warning @koinos/sdk-as > @koinos/mock-vm > somap > npm > readdir-scoped-modules@1.1.0: This functionality has been moved to @npmcli/fs
warning @koinos/sdk-as > @koinos/mock-vm > somap > npm > @npmcli/arborist > readdir-scoped-modules@1.1.0: This functionality has been moved to @npmcli/fs
warning @koinos/sdk-as > @koinos/mock-vm > somap > npm > @npmcli/arborist > @npmcli/move-file@2.0.1: This functionality has been moved to @npmcli/fs
warning @koinos/sdk-as > @koinos/mock-vm > somap > npm > cacache > @npmcli/move-file@2.0.1: This functionality has been moved to @npmcli/fs
warning @koinos/sdk-as > @koinos/mock-vm > somap > npm > readdir-scoped-modules > debuglog@1.0.1: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
warning local-koinos > koilib > multibase@4.0.6: This module has been superseded by the multiformats module
[2/4] Fetching packages...
[3/4] Linking dependencies...
warning "@koinos/sdk-as > @as-covers/core > @as-covers/transform > visitor-as@0.6.0" has incorrect peer dependency "assemblyscript@^0.18.31".
warning " > ts-node@10.9.2" has unmet peer dependency "@types/node@*".
warning Workspaces can only be enabled in private projects.
[4/4] Building fresh packages...
success Saved lockfile.
Done in 62.51s.
Generating the authorize stubs¶
Because we are creating an immutable contract we will invoke the koinos-sdk-as-cli
in order to stub out the implementation for us. We can leave the boilerplate "Hello World" implementation in assembly/immutable/proto/immutable.proto
and assembly/Immutable.ts
.
koinos-sdk-as-cli generate-contract-as --generate_authorize immutable.proto
Generating boilerplate.ts and index.ts files...
GENERATE_AUTHORIZE_ENTRY_POINT=1 yarn protoc --plugin=protoc-gen-as=./node_modules/.bin/koinos-as-gen --as_out=assembly/ assembly/proto/immutable.proto
yarn run v1.22.22
$ /home/$USER/Workspace/immutable/node_modules/.bin/protoc --plugin=protoc-gen-as=./node_modules/.bin/koinos-as-gen --as_out=assembly/ assembly/proto/immutable.proto
@protobuf-ts/protoc installed protoc v26.1.
Done in 5.07s.
In the following code snippets the highlighted lines were added by the previous invocation.
assembly/index.ts | |
---|---|
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 |
|
assembly/Immutable.boilerplate.ts | |
---|---|
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 |
|
When we originally created this smart contract, we were given an example implementation of Hello World. Let's copy that code and move it to our new boiler plate file.
assembly/Immutable.ts | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
With the implementation copied into our boilerplate it should look like the following snippet.
assembly/Immutable.boilerplate.ts | |
---|---|
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 |
|
Excellent! Now we have can replace the entire Immutable.ts
file with our Immutable.boilerplate.ts
contents.
rm assembly/Immutable.ts
mv assembly/Immutable.boilerplate.ts assembly/Immutable.ts
Now we move on to the crux of the matter, making our smart contract immutable!
The implementation¶
To make a contract immutable, we must indicate that it cannot be re-uploaded. The authority system is capable of more complex decisions and it is recommended to read about it in the Authority section. Let's demonstrate an implementation that locks down the contract and enforces immutability.
Open up your implementation file.
vi assembly/Immutable.ts
To accomplish this, we simply return false
from the authorize()
method.
assembly/Immutable.ts | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Building the contract¶
Great! It's time to build our contract. Before proceeding let's generate the AssemblyScript code for our "Hello World" implementation.
koinos-sdk-as-cli generate-contract-proto
Generating Contract AS proto files...
yarn protoc --plugin=protoc-gen-as=./node_modules/.bin/as-proto-gen --as_out=. assembly/proto/*.proto
yarn run v1.22.22
$ /home/$USER/Workspace/immutable/node_modules/.bin/protoc --plugin=protoc-gen-as=./node_modules/.bin/as-proto-gen --as_out=. assembly/proto/immutable.proto
Done in 0.60s.
Note
This generates the file assembly/proto/immutable.ts
with the following contents.
assembly/proto/immutable.ts | |
---|---|
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 69 70 71 72 73 74 75 |
|
This code is for serialization and deserialization of the "Hello World" method and is not related to making our contract immutable.
And finally, we build it.
koinos-sdk-as-cli build debug 0
Compiling index.ts...
node ./node_modules/assemblyscript/bin/asc assembly/index.ts --target debug --use abort= --use BUILD_FOR_TESTING=0 --disable sign-extension --config asconfig.json
Time for tests¶
Since we are using the default "Hello World" implementation, we were given our test for free. Let's have a look at the test file provided.
cat assembly/__tests__/Immutable.spec.ts
assembly/__tests__/Immutable.spec.ts | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Why don't we do our due diligence and ensure our authorize()
method actually returns false
by adding a test.
vi assembly/__tests__/Immutable.spec.ts
Add the following highlighted lines.
assembly/__tests__/Immutable.spec.ts | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
And finally, let's run our tests.
koinos-sdk-as-cli run-tests
Running tests...
yarn asp --verbose --config as-pect.config.js
yarn run v1.22.22
$ /home/$USER/Workspace/immutable/node_modules/.bin/asp --verbose --config as-pect.config.js
___ _____ __
/ | / ___/ ____ ___ _____/ /_
/ /| | \__ \______/ __ \/ _ \/ ___/ __/
/ ___ |___/ /_____/ /_/ / __/ /__/ /_
/_/ |_/____/ / .___/\___/\___/\__/
/_/
⚡AS-pect⚡ Test suite runner [6.2.4]
[Log] Loading asc compiler
Assemblyscript Folder:assemblyscript
[Log] Compiler loaded in 171.92ms.
[Log] Using configuration /home/$USER/Workspace/immutable/as-pect.config.js
[Log] Using VerboseReporter
[Log] Including files: assembly/__tests__/**/*.spec.ts
[Log] Running tests that match: (:?)
[Log] Running groups that match: (:?)
[Log] Effective command line args:
[TestFile.ts] node_modules/@as-pect/assembly/assembly/index.ts --runtime incremental --debug --binaryFile output.wasm --explicitStart --use ASC_RTRACE=1 --exportTable --importMemory --transform /home/$USER/Workspace/immutable/node_modules/@as-covers/transform/lib/index.js,/home/$USER/Workspace/immutable/node_modules/@as-pect/core/lib/transform/index.js --lib node_modules/@as-covers/assembly/index.ts
[Describe]: contract
[Log] Hello, World!
[Success]: ✔ should return 'hello, NAME!' RTrace: +21
[Success]: ✔ should not authorize RTrace: +14
[File]: assembly/__tests__/Immutable.spec.ts
[Groups]: 2 pass, 2 total
[Result]: ✔ PASS
[Snapshot]: 0 total, 0 added, 0 removed, 0 different
[Summary]: 2 pass, 0 fail, 2 total
[Time]: 15.483ms
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[Result]: ✔ PASS
[Files]: 1 total
[Groups]: 2 count, 2 pass
[Tests]: 2 pass, 0 fail, 2 total
[Time]: 2522.981ms
┌───────────────────────┬───────┬───────┬──────┬──────┬───────────┐
│ File │ Total │ Block │ Func │ Expr │ Uncovered │
├───────────────────────┼───────┼───────┼──────┼──────┼───────────┤
│ assembly/Immutable.ts │ 100% │ 100% │ 100% │ N/A │ │
├───────────────────────┼───────┼───────┼──────┼──────┼───────────┤
│ total │ 100% │ 100% │ 100% │ N/A │ │
└───────────────────────┴───────┴───────┴──────┴──────┴───────────┘
Done in 2.71s.
Awesome, you have written a basic smart contract that is immutable with unit tests! Bravo!
Note
It is not enough to just implement authorize()
in your smart contract. You must indicate that you are overriding the authorize()
function when uploading your smart contract. For details and examples of how this works check out the Authority: Uploading the contract section.
For more information on uploading contracts, visit the Deploying a contract.