Skip to content

Commit

Permalink
Add example Solana contract using the sealable trie (#3)
Browse files Browse the repository at this point in the history
Introduce solana/trie-example smart contract which uses the sealable
trie on Solana chain.  The contract as well as its client are quite
rudimentary but they allow demonstrating working code.
  • Loading branch information
mina86 authored Aug 22, 2023
1 parent 5f3c85f commit 1801472
Show file tree
Hide file tree
Showing 15 changed files with 958 additions and 4 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
target/
/target/
/dist/
/node_modules/
package-lock.json
Cargo.lock
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ rust-version = "1.71.0"
members = [
"memory",
"sealable-trie",
"solana/trie-example",
"stdx",
]
resolver = "2"
Expand All @@ -18,6 +19,9 @@ derive_more = "0.99.17"
pretty_assertions = "1.4.0"
rand = { version = "0.8.5" }
sha2 = { version = "0.10.7", default-features = false }
solana-client = "1.16.7"
solana-program = "1.16.7"
solana-sdk = "1.16.7"
strum = { version = "0.25.0", default-features = false, features = ["derive"] }

memory = { path = "memory" }
Expand Down
45 changes: 45 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
## Composable Finance Business License 1.0

### Parameters

**Licensor:** Composable Finance Ltd.
**Licensed Work:** Emulated Light Client
**Date of License Change:** August 20, 2024
**Changed License:** GNU General Public License v2.0 or later
**Other Permitted Use:** N/A

### Notice

Under the Composable Finance Business License 1.0 (the "License"), use of any code, text, file or anything found within this repository in relation to the Licensed Work, may be granted to a Licensee under the terms of this notice and other applicable agreements and documents (the "Notice").

The License is not open source in nature but it is intended to eventually become open source under the terms set forth herein.

### Terms

1. Unauthorized use, copying, modification, creation of derivative works, and redistribution of the Licensed Work by third parties is prohibited without obtaining a License from the Licensor.

1. A License shall be granted to you which shall come with certain rights and obligations under a licensing agreement entered or to be entered by you and the Licensor (the "Licensing Agreement"). The License shall be a commercial, non-exclusive, non-sublicensable, and non-transferable license to use the Licensed Work, subject to all the terms, conditions, duration, and restrictions under the underlying Licensing Agreement. Any use of the Licensed Work in violation of the License will automatically terminate your rights under the License for the current and all other versions of the Licensed Work.

1. These Terms shall be subject to the Parameters above which are specifically described below as follows:

1. Licensor: The author, inventor, assignee, or owner or of the Licensed Work.
2. Licensed Work: The licensed software or work of the Licensor subject to the License.
3. Date of License Change: The date when the License is converted to the Changed License.
4. Changed License: The license type to which the License will be converted to on the Date of License Change.
5. Other Permitted Use: The uses or rights specifically granted to you beyond those stated in this Notice and as may be allowed under the Licensing Agreement.

1. Effective on the Date of License Change, your rights and obligations shall be governed by the terms and conditions of the Changed License, and the rights granted to you under this License shall terminate.

1. All copies of the original and modified Licensed Work, and derivative work of the Licensed Work, shall be subject to this License. This License shall apply separately for each version of the Licensed Work and the Date of License Change may vary for each version of the Licensed Work released by the Licensor.

1. The License does not grant you any right in any trademark or logo of Licensor or its affiliates. Provided that, you may use a trademark or logo of the Licensor if expressly allowed or required by the Licensing Agreement.

1. TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK SHALL BE PROVIDED ON AN "AS IS" BASIS. THE LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND TITLE.

1. You shall be required to conspicuously display this Notice on each original or modified copy of the Licensed Work.

1. The Terms in this Notice shall be consistent with the more comprehensive set of terms, conditions, restrictions and limitations of the Licensing Agreement executed or to be executed between you and the Licensor. In case of conflict, the terms of the License Agreement shall prevail over this Notice.

### Copyright on License Text

Composable Finance shall grant you the permission to use this Notice's text for your works that make use of the Licensed Work, and to refer to it using the trademark "Composable Finance Business License 1.0" for the limited purpose of referring to the License and complying with the requirements of its display.
5 changes: 4 additions & 1 deletion deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ allow-registry = ["https://github.com/rust-lang/crates.io-index"]
allow-git = []

[bans]
multiple-versions = "deny"
# solana-program is weird and has bunch of duplicate dependencies.
# For now allow duplicates. TODO(mina86): Figure out if there’s
# something better we can do.
multiple-versions = "allow"
skip = [
# derive_more still uses old syn
{ name = "syn", version = "1.0.*" },
Expand Down
43 changes: 43 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"name": "solana-trie-example",
"version": "0.0.1",
"author": "Michał Nazarewicz <[email protected]>",
"scripts": {
"start": "ts-node solana/trie-example/client/main.ts",
"start-with-test-validator": "start-server-and-test 'solana-test-validator --reset --quiet' http://localhost:8899/health start",
"lint": "eslint --ext .ts solana/trie-example/* && prettier --check \"solana/trie-example/**/*.ts\"",
"lint:fix": "eslint --ext .ts solana/trie-example/* --fix && prettier --write \"solana/trie-example/**/*.ts\"",
"clean": "npm run clean:trie-example",
"build:trie-example": "cargo build-sbf --manifest-path=solana/trie-example/Cargo.toml --sbf-out-dir=dist/trie-example",
"deploy:trie-example": "solana program deploy dist/trie-example/trie.so",
"clean:trie-example": "cargo clean --manifest-path=solana/trie-example/Cargo.toml && rm -rf ./dist",
"test:trie-example": "cargo test-bpf --manifest-path=solana/trie-example/Cargo.toml",
"pretty": "prettier --write 'solana/trie-example/client/*.ts'"
},
"dependencies": {
"@solana/web3.js": "^1.33.0",
"mz": "^2.7.0",
"tsconfig": "^7.0.0",
"yaml": "^2.0.0"
},
"devDependencies": {
"@tsconfig/recommended": "^1.0.1",
"@types/eslint": "^8.2.2",
"@types/eslint-plugin-prettier": "^3.1.0",
"@types/mz": "^2.7.2",
"@types/prettier": "^2.1.5",
"@types/yaml": "^1.9.7",
"@typescript-eslint/eslint-plugin": "^4.6.0",
"@typescript-eslint/parser": "^4.6.0",
"eslint": "^7.12.1",
"eslint-config-prettier": "^6.15.0",
"eslint-plugin-prettier": "^4.0.0",
"prettier": "^2.1.2",
"start-server-and-test": "^1.11.6",
"ts-node": "^10.0.0",
"typescript": "^4.0.5"
},
"engines": {
"node": ">=14.0.0"
}
}
2 changes: 1 addition & 1 deletion sealable-trie/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ pub mod trie;
#[cfg(test)]
mod test_utils;

pub use trie::Trie;
pub use trie::{Error, Trie};
21 changes: 20 additions & 1 deletion sealable-trie/src/trie.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ macro_rules! proof {
}

impl<A: memory::Allocator<Value = Value>> Trie<A> {
/// Creates a new trie using given allocator.
/// Creates a new empty trie using given allocator.
pub fn new(alloc: A) -> Self {
Self { root_ptr: None, root_hash: EMPTY_TRIE_ROOT, alloc }
}
Expand All @@ -117,6 +117,25 @@ impl<A: memory::Allocator<Value = Value>> Trie<A> {
/// Returns whether the trie is empty.
pub fn is_empty(&self) -> bool { self.root_hash == EMPTY_TRIE_ROOT }

/// Deconstructs the object into the individual parts — allocator, root
/// pointer and root hash.
pub fn into_parts(self) -> (A, Option<Ptr>, CryptoHash) {
(self.alloc, self.root_ptr, self.root_hash)
}

/// Creates a new trie from individual parts.
///
/// It’s up to the caller to guarantee that the `root_ptr` and `root_hash`
/// values are correct and correspond to nodes stored within the pool
/// allocator `alloc`.
pub fn from_parts(
alloc: A,
root_ptr: Option<Ptr>,
root_hash: CryptoHash,
) -> Self {
Self { root_ptr, root_hash, alloc }
}

/// Retrieves value at given key.
///
/// Returns `None` if there’s no value at given key. Returns an error if
Expand Down
17 changes: 17 additions & 0 deletions solana/trie-example/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "solana-trie-example"
authors = ["Michal Nazarewicz <[email protected]>"]
version = "0.0.0"
edition = "2021"

[lib]
name = "trie"
crate-type = ["cdylib", "lib"]

[dependencies]
derive_more.workspace = true
solana-program.workspace = true

memory.workspace = true
sealable-trie.workspace = true
stdx.workspace = true
75 changes: 75 additions & 0 deletions solana/trie-example/client/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import {
establishConnection,
establishPayer,
checkProgram,
getKey,
setKey,
sealKey,
} from './trie';

async function main() {
const operation = parseArgv(process.argv);
if (!operation) {
return;
}

// Establish connection to the cluster
await establishConnection();

// Determine who pays for the fees
await establishPayer();

// Check if the program has been deployed
await checkProgram();

switch (operation[0]) {
case "get":
await getKey(operation[1]);
break;
case "set":
await setKey(operation[1], operation[2]);
break;
case "seal":
await sealKey(operation[1]);
break;
}

console.log('Success');
}

function parseArgv(argv: string[]): string[] | null {
const cmd = argv[0] + ' ' + argv[1];
switch (argv[2] || "--help") {
case "get":
case "seal":
if (argv.length != 4) {
break;
}
return [argv[2], argv[3]];
case "set":
if (argv.length != 5) {
break;
}
return [argv[2], argv[3], argv[4]];
case "help":
case "--help":
case "-h": {
console.log(
`usage: ${cmd} get <hex-key>\n` +
` ${cmd} set <hex-key> <hex-hash>\n` +
` ${cmd} seal <hex-key>`
)
process.exit(0);
}
}
console.error(`Invalid usage; see ${cmd} --help`);
process.exit(-1);
}

main().then(
() => process.exit(),
err => {
console.error(err);
process.exit(-1);
},
);
Loading

0 comments on commit 1801472

Please sign in to comment.