Skip to content

Commit

Permalink
Merge pull request #2 from Anastasia-Labs/linked-list
Browse files Browse the repository at this point in the history
add sample validator
  • Loading branch information
hadelive authored Jan 30, 2024
2 parents 54e72cb + 5989d10 commit c1edb1f
Show file tree
Hide file tree
Showing 5 changed files with 556 additions and 11 deletions.
2 changes: 2 additions & 0 deletions lib/linkedlist/constants.ak
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
pub const origin_node_token_name = "FSN"

pub const set_node_prefix = "FSN"
10 changes: 4 additions & 6 deletions lib/linkedlist/linked_list.ak
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use aiken/bytearray
use aiken/interval
use aiken/interval.{Interval}
use aiken/list
use aiken/transaction.{Output}
use aiken/transaction/value.{lovelace_of}
Expand All @@ -8,7 +8,7 @@ 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_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(
Expand Down Expand Up @@ -63,7 +63,7 @@ pub fn insert(common: Common, insert_key: PubKeyHash, node: SetNode) -> Bool {

pub fn remove(
common: Common,
range: POSIXTime,
range: Interval<POSIXTime>,
disc_config: Config,
outs: List<Output>,
sigs: List<PubKeyHash>,
Expand Down Expand Up @@ -92,9 +92,7 @@ pub fn remove(
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){

if interval.is_entirely_before(range, disc_deadline) {
True
} else {
list.any(
Expand Down
4 changes: 2 additions & 2 deletions lib/linkedlist/types.ak
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@ pub type Common {
pub type NodeAction {
Init
Deinit
Insert
Remove
Insert { key_to_insert: PubKeyHash, covering_node: SetNode }
Remove { key_to_remove: PubKeyHash, covering_node: SetNode }
}
159 changes: 156 additions & 3 deletions lib/linkedlist/utils.ak
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
use aiken/bytearray
use aiken/dict
use aiken/transaction/value.{Value}
use linkedlist/types.{Empty, Key, PubKeyHash, SetNode}
use aiken/dict.{has_key}
use aiken/interval.{Interval}
use aiken/list
use aiken/transaction.{
InlineDatum, Input, Mint, Output, ScriptContext, Transaction,
}
use aiken/transaction/value.{
AssetName, PolicyId, Value, flatten, from_minted_value, to_dict, tokens,
}
use linkedlist/constants.{set_node_prefix}
use linkedlist/types.{
Common, Empty, Key, NodePair, POSIXTime, PubKeyHash, SetNode,
}

pub fn validate_mint(
mints: Value,
Expand Down Expand Up @@ -43,3 +53,146 @@ pub fn div_ceil(a, b: Int) -> Int {
_ -> div + 1
}
}

pub fn make_common(
ctx: ScriptContext,
) -> (Common, List<Input>, List<Output>, List<PubKeyHash>, Interval<POSIXTime>) {
expect ScriptContext {
transaction: Transaction {
inputs,
outputs,
mint,
validity_range,
extra_signatories,
..
},
purpose: Mint(own_cs),
} = ctx
let in_outputs = get_outputs(inputs)
let from_node_val = only_at_node_val(in_outputs, own_cs)
let to_node_val = only_at_node_val(outputs, own_cs)
expect Some(head) = list.head(list.concat(from_node_val, to_node_val))
let Output { address: node_address, .. } = head
expect
from_node_val
|> list.concat(to_node_val)
|> list.reduce(
True,
fn(acc, cur_node) {
let Output { address: cur_address, .. } = cur_node
and {
cur_address == node_address,
acc,
}
},
)
let node_inputs = list.map(from_node_val, node_input_utxo_datum_unsafe)
let node_outputs =
list.map(to_node_val, fn(node) { parse_node_output_utxo(own_cs, node) })
let common =
Common { own_cs, mint: from_minted_value(mint), node_inputs, node_outputs }
(common, inputs, outputs, extra_signatories, validity_range)
}

// Checks if a Currency Symbol is held within a Value
pub fn has_data_cs(cs: PolicyId, value: Value) -> Bool {
value
|> to_dict()
|> has_key(cs)
}

pub fn get_outputs(inputs: List<Input>) -> List<Output> {
list.map(
inputs,
fn(input) {
let Input { output, .. } = input
output
},
)
}

pub fn only_at_node_val(outputs: List<Output>, cs: PolicyId) -> List<Output> {
outputs
|> list.filter(
fn(output) {
let Output { value, .. } = output
has_data_cs(cs, value)
},
)
}

pub fn node_input_utxo_datum_unsafe(output: Output) -> NodePair {
expect Output { value, datum: InlineDatum(raw_node), .. } = output
expect node: SetNode = raw_node
NodePair { val: value, node }
}

pub fn parse_node_output_utxo(cs: PolicyId, output: Output) -> NodePair {
expect Output { value, datum: InlineDatum(raw_node), .. } = output
expect node: SetNode = raw_node
expect [(tn, amount)] =
value
|> tokens(cs)
|> dict.to_list()
expect amount == 1
let node_key = parse_node_key(tn)
let datum_key =
when node.key is {
Empty -> None
Key(key) -> Some(key)
}
expect node_key == datum_key
expect list.length(flatten(value)) == 2
expect valid_node(node)
expect find_cs_by_token_prefix(value, set_node_prefix) == [cs]
NodePair { val: value, node }
}

pub fn parse_node_key(tn: AssetName) -> Option<ByteArray> {
let prefix_length = bytearray.length(set_node_prefix)
let tn_length = bytearray.length(tn)
let key = bytearray.drop(tn, prefix_length)
expect set_node_prefix == bytearray.take(tn, prefix_length)
when prefix_length < tn_length is {
True -> Some(key)
False -> None
}
}

pub fn valid_node(node: SetNode) -> Bool {
when node.key is {
Empty -> True
Key(node_key) ->
when node.next is {
Empty -> True
Key(next_key) -> bytearray.compare(node_key, next_key) == Less
}
}
}

pub fn find_cs_by_token_prefix(
value: Value,
prefix: ByteArray,
) -> List<PolicyId> {
value
|> flatten
|> list.filter_map(
fn(input: (PolicyId, ByteArray, Int)) -> Option<PolicyId> {
let (cs, tn, _amt) = input
if is_prefix_of(prefix, tn) {
Some(cs)
} else {
None
}
},
)
}

pub fn is_prefix_of(prefix: ByteArray, src: ByteArray) -> Bool {
let prefix_length = bytearray.length(prefix)
let src_length = bytearray.length(src)
when prefix_length <= src_length is {
True -> bytearray.take(src, prefix_length) == prefix
False -> False
}
}
Loading

0 comments on commit c1edb1f

Please sign in to comment.