-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from Anastasia-Labs/linked-list
Add linked list lib
- Loading branch information
Showing
10 changed files
with
299 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
name: Tests | ||
|
||
on: | ||
push: | ||
branches: ["main"] | ||
pull_request: | ||
branches: ["main"] | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
|
||
- uses: aiken-lang/[email protected] | ||
with: | ||
version: v1.0.21-alpha | ||
|
||
- run: aiken fmt --check | ||
- run: aiken check | ||
- run: aiken build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
.DS_Store | ||
build | ||
.VSCodeCounter | ||
plutus.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,13 @@ | ||
# aiken-linked-list | ||
# aiken-linked-list | ||
|
||
## Building | ||
|
||
```sh | ||
aiken build | ||
``` | ||
|
||
To run all tests, simply do: | ||
|
||
```sh | ||
aiken check | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# This file was generated by Aiken | ||
# You typically do not need to edit this file | ||
|
||
[[requirements]] | ||
name = "aiken-lang/stdlib" | ||
version = "1.7.0" | ||
source = "github" | ||
|
||
[[packages]] | ||
name = "aiken-lang/stdlib" | ||
version = "1.7.0" | ||
requirements = [] | ||
source = "github" | ||
|
||
[etags] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
name = "aiken-lang/aiken-linked-list" | ||
version = "0.0.0" | ||
license = "Apache-2.0" | ||
description = "Aiken contracts for project 'aiken-lang/aiken-linked-list'" | ||
|
||
[repository] | ||
user = "aiken-lang" | ||
project = "aiken-linked-list" | ||
platform = "github" | ||
|
||
[[dependencies]] | ||
name = "aiken-lang/stdlib" | ||
version = "1.7.0" | ||
source = "github" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub const origin_node_token_name = "FSN" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
use aiken/bytearray | ||
use aiken/interval | ||
use aiken/list | ||
use aiken/transaction.{Output} | ||
use aiken/transaction/value.{lovelace_of} | ||
use linkedlist/constants | ||
use linkedlist/types.{Common, Config, POSIXTime, PubKeyHash, SetNode} | ||
use linkedlist/utils | ||
|
||
pub fn init(common: Common) -> Bool { | ||
let must_spend_nodes = list.length(common.node_inputs) > 0 | ||
let must_exactly_one_node_output = list.length(common.node_outputs) == 1 | ||
let must_mint_correctly = | ||
utils.validate_mint( | ||
common.mint, | ||
common.own_cs, | ||
constants.origin_node_token_name, | ||
1, | ||
) | ||
must_spend_nodes? && must_exactly_one_node_output? && must_mint_correctly? | ||
} | ||
|
||
pub fn deinit(common: Common) -> Bool { | ||
let must_spend_exactly_one_node_input = list.length(common.node_inputs) == 1 | ||
let must_not_produce_node_output = list.length(common.node_outputs) == 0 | ||
let must_burn_correctly = | ||
utils.validate_mint( | ||
common.mint, | ||
common.own_cs, | ||
constants.origin_node_token_name, | ||
-1, | ||
) | ||
must_spend_exactly_one_node_input? && must_not_produce_node_output? && must_burn_correctly? | ||
} | ||
|
||
pub fn insert(common: Common, insert_key: PubKeyHash, node: SetNode) -> Bool { | ||
let must_cover_inserting_key = utils.cover_key(node, insert_key) | ||
expect [covering_node] = common.node_inputs | ||
let prev_node_datum = utils.as_predecessor_of(node, insert_key) | ||
let node_datum = utils.as_successor_of(insert_key, node) | ||
let must_has_datum_in_output = | ||
list.any( | ||
common.node_outputs, | ||
fn(node_pair) { node_datum == node_pair.node }, | ||
) | ||
let must_correct_node_output = | ||
list.any( | ||
common.node_outputs, | ||
fn(node_pair) { | ||
covering_node.val == node_pair.val && prev_node_datum == node_pair.node | ||
}, | ||
) | ||
|
||
let must_mint_correct = | ||
utils.validate_mint( | ||
common.mint, | ||
common.own_cs, | ||
bytearray.concat(constants.origin_node_token_name, insert_key), | ||
1, | ||
) | ||
must_cover_inserting_key? && must_has_datum_in_output? && must_correct_node_output? && must_mint_correct? | ||
} | ||
|
||
pub fn remove( | ||
common: Common, | ||
range: POSIXTime, | ||
disc_config: Config, | ||
outs: List<Output>, | ||
sigs: List<PubKeyHash>, | ||
remove_key: PubKeyHash, | ||
node: SetNode, | ||
) -> Bool { | ||
let must_cover_remove_key = utils.cover_key(node, remove_key) | ||
let prev_node_datum = utils.as_predecessor_of(node, remove_key) | ||
let node_datum = utils.as_successor_of(remove_key, node) | ||
let must_spend_two_nodes = list.length(common.node_inputs) == 2 | ||
expect Some(stay_node) = | ||
list.find(common.node_inputs, fn(input) { prev_node_datum == input.node }) | ||
expect Some(remove_node) = | ||
list.find(common.node_inputs, fn(input) { node_datum == input.node }) | ||
let remove_token_name = | ||
bytearray.concat(constants.origin_node_token_name, remove_key) | ||
let must_correct_node_output = | ||
list.any( | ||
common.node_outputs, | ||
fn(node_pair) { stay_node.val == node_pair.val && node == node_pair.node }, | ||
) | ||
let must_mint_correct = | ||
utils.validate_mint(common.mint, common.own_cs, remove_token_name, -1) | ||
let must_sign_by_user = list.has(sigs, remove_key) | ||
let own_input_lovelace = lovelace_of(remove_node.val) | ||
let own_input_fee = utils.div_ceil(own_input_lovelace, 4) | ||
let disc_deadline = disc_config.deadline | ||
let must_satisfy_removal_broke_phase_rules = | ||
if | ||
interval.is_entirely_after(interval.after(disc_deadline - 8_640_000), range){ | ||
|
||
True | ||
} else { | ||
list.any( | ||
outs, | ||
fn(out) { | ||
out.address == disc_config.penalty_address && own_input_fee < lovelace_of( | ||
out.value, | ||
) | ||
}, | ||
) | ||
} | ||
must_cover_remove_key? && must_spend_two_nodes? && must_correct_node_output? && must_mint_correct? && must_sign_by_user? && must_satisfy_removal_broke_phase_rules? | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
use linkedlist/utils.{div_ceil} | ||
|
||
// Test Case 1 | ||
// Test when a is divisible by b | ||
test div_ceil_1() { | ||
div_ceil(10, 5) == 2 | ||
} | ||
|
||
// Test Case 2 | ||
// Test when a is not divisible by b | ||
test div_ceil_2() { | ||
div_ceil(7, 3) == 3 | ||
} | ||
|
||
// Test Case 3 | ||
// Test when a is 0 | ||
test div_ceil_3() { | ||
div_ceil(0, 5) == 0 | ||
} | ||
|
||
// Test Case 4 | ||
// Test when b is 1 | ||
test div_ceil_4() { | ||
div_ceil(10, 1) == 10 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
use aiken/hash.{Blake2b_224, Hash} | ||
use aiken/transaction.{OutputReference} | ||
use aiken/transaction/credential.{Address, VerificationKey} | ||
use aiken/transaction/value.{AssetName, PolicyId, Value} | ||
|
||
/// A number of milliseconds since 00:00:00 UTC on 1 January 1970. | ||
pub type POSIXTime = | ||
Int | ||
|
||
pub type AssetClass { | ||
policy_id: PolicyId, | ||
asset_name: AssetName, | ||
} | ||
|
||
pub type PubKeyHash = | ||
Hash<Blake2b_224, VerificationKey> | ||
|
||
pub type Config { | ||
init_utxo: OutputReference, | ||
deadline: POSIXTime, | ||
penalty_address: Address, | ||
} | ||
|
||
pub type NodeKey { | ||
Key { key: PubKeyHash } | ||
Empty | ||
} | ||
|
||
pub type SetNode { | ||
key: NodeKey, | ||
next: NodeKey, | ||
} | ||
|
||
pub type NodePair { | ||
val: Value, | ||
node: SetNode, | ||
} | ||
|
||
pub type Common { | ||
own_cs: PolicyId, | ||
mint: Value, | ||
node_inputs: List<NodePair>, | ||
node_outputs: List<NodePair>, | ||
} | ||
|
||
pub type NodeAction { | ||
Init | ||
Deinit | ||
Insert | ||
Remove | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
use aiken/bytearray | ||
use aiken/dict | ||
use aiken/transaction/value.{Value} | ||
use linkedlist/types.{Empty, Key, PubKeyHash, SetNode} | ||
|
||
pub fn validate_mint( | ||
mints: Value, | ||
expected_minting_policy: ByteArray, | ||
expected_minting_name: ByteArray, | ||
expected_minting_amt: Int, | ||
) -> Bool { | ||
let mints_policy = dict.to_list(value.tokens(mints, expected_minting_policy)) | ||
mints_policy == [(expected_minting_name, expected_minting_amt)] | ||
} | ||
|
||
pub fn cover_key(node: SetNode, insert_key: PubKeyHash) -> Bool { | ||
let less_than_key = | ||
when node.key is { | ||
Empty -> True | ||
Key(key) -> bytearray.compare(key, insert_key) == Less | ||
} | ||
let more_than_key = | ||
when node.next is { | ||
Empty -> True | ||
Key(key) -> bytearray.compare(key, insert_key) == Greater | ||
} | ||
less_than_key? && more_than_key? | ||
} | ||
|
||
pub fn as_predecessor_of(node: SetNode, next_key: PubKeyHash) -> SetNode { | ||
SetNode { key: node.key, next: Key(next_key) } | ||
} | ||
|
||
pub fn as_successor_of(prev_key: PubKeyHash, node: SetNode) -> SetNode { | ||
SetNode { key: Key(prev_key), next: node.next } | ||
} | ||
|
||
pub fn div_ceil(a, b: Int) -> Int { | ||
let div = a / b | ||
let rem = a % b | ||
when rem is { | ||
0 -> div | ||
_ -> div + 1 | ||
} | ||
} |