Skip to content

Commit deff38c

Browse files
authored
Merge pull request #27 from hyperledger/doc-improvements
Doc improvements
2 parents 1241be9 + d283832 commit deff38c

File tree

20 files changed

+389
-294
lines changed

20 files changed

+389
-294
lines changed

Cargo.lock

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

firefly-balius/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "firefly-balius"
3-
version = "0.3.0"
3+
version = "0.3.1"
44
description = "Helpers to write contracts for the FireFly Cardano connector"
55
license-file.workspace = true
66
publish = false

firefly-balius/src/events.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use std::collections::HashMap;
2+
3+
use balius_sdk::{Utxo, WorkerResult};
4+
use serde::{Deserialize, Serialize};
5+
6+
use crate::kv;
7+
8+
pub trait EventData: Serialize {
9+
fn signature(&self) -> String;
10+
}
11+
12+
#[derive(Serialize, Deserialize)]
13+
pub struct Event {
14+
pub block_hash: Vec<u8>,
15+
pub tx_hash: Vec<u8>,
16+
pub signature: String,
17+
pub data: serde_json::Value,
18+
}
19+
20+
impl Event {
21+
pub fn new<D, E: EventData>(utxo: &Utxo<D>, data: &E) -> WorkerResult<Self> {
22+
Ok(Self {
23+
block_hash: utxo.block_hash.clone(),
24+
tx_hash: utxo.tx_hash.clone(),
25+
signature: data.signature(),
26+
data: serde_json::to_value(data)?,
27+
})
28+
}
29+
}
30+
31+
pub fn emit_events(events: Vec<Event>) -> WorkerResult<()> {
32+
if events.is_empty() {
33+
return Ok(());
34+
}
35+
36+
let mut block_events: HashMap<String, Vec<Event>> = HashMap::new();
37+
for event in events {
38+
let block_hash = hex::encode(&event.block_hash);
39+
block_events.entry(block_hash).or_default().push(event);
40+
}
41+
42+
for (block, mut events) in block_events {
43+
let events_key = format!("__events_{block}");
44+
let mut all_events: Vec<Event> = kv::get(&events_key)?.unwrap_or_default();
45+
all_events.append(&mut events);
46+
kv::set(&events_key, &all_events)?;
47+
}
48+
49+
Ok(())
50+
}

firefly-balius/src/kv.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use balius_sdk::{wit::balius::app::kv, WorkerResult};
2+
use serde::{Deserialize, Serialize};
3+
4+
pub fn get<D: for<'a> Deserialize<'a>>(key: &str) -> WorkerResult<Option<D>> {
5+
match kv::get_value(key) {
6+
Ok(bytes) => Ok(Some(serde_json::from_slice(&bytes)?)),
7+
Err(kv::KvError::NotFound(_)) => Ok(None),
8+
Err(err) => Err(err.into()),
9+
}
10+
}
11+
12+
pub fn set<S: Serialize>(key: &str, value: &S) -> WorkerResult<()> {
13+
kv::set_value(key, &serde_json::to_vec(value)?)?;
14+
Ok(())
15+
}

firefly-balius/src/lib.rs

Lines changed: 10 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -1,174 +1,10 @@
1-
use std::{collections::HashMap, marker::PhantomData};
2-
3-
use balius_sdk::{
4-
txbuilder::{primitives::TransactionInput, BuildContext, BuildError, InputExpr, UtxoSource},
5-
wit, Ack, Params, Utxo, Worker, WorkerResult,
6-
_internal::Handler,
7-
};
8-
use serde::{Deserialize, Serialize};
9-
10-
pub struct CoinSelectionInput(pub UtxoSource, pub u64);
11-
12-
// TODO: this is a naive approach to coin selection,
13-
// balius can probably help with a better one
14-
impl InputExpr for CoinSelectionInput {
15-
fn eval(&self, ctx: &BuildContext) -> Result<Vec<TransactionInput>, BuildError> {
16-
let utxos = self.0.resolve(ctx)?;
17-
// If we know the fee, add it to the target amount.
18-
// If not, overestimate the fee so we pick at least as many TXOs as needed.
19-
let target_lovelace = self.1
20-
+ if ctx.estimated_fee == 0 {
21-
2_000_000
22-
} else {
23-
ctx.estimated_fee
24-
};
25-
26-
let mut inputs = vec![];
27-
let mut lovelace_so_far = 0;
28-
let mut pairs: Vec<_> = utxos.iter().collect();
29-
pairs.sort_by_key(|(ref_, _)| (ref_.hash, ref_.index));
30-
for (ref_, txo) in pairs {
31-
let coin = txo.value().coin();
32-
if coin == 0 {
33-
continue;
34-
}
35-
inputs.push(TransactionInput {
36-
transaction_id: ref_.hash,
37-
index: ref_.index,
38-
});
39-
lovelace_so_far += coin;
40-
if lovelace_so_far >= target_lovelace {
41-
break;
42-
}
43-
}
44-
if lovelace_so_far >= target_lovelace {
45-
Ok(inputs)
46-
} else {
47-
Err(BuildError::OutputsTooHigh)
48-
}
49-
}
50-
}
51-
52-
#[derive(Deserialize)]
53-
pub struct SubmittedTx {
54-
pub method: String,
55-
pub hash: String,
56-
}
57-
58-
pub struct SubmittedTxHandler<F, C>
59-
where
60-
F: Fn(C, SubmittedTx) -> WorkerResult<Ack> + 'static,
61-
C: TryFrom<wit::Config>,
62-
{
63-
func: F,
64-
phantom: PhantomData<C>,
65-
}
66-
67-
impl<F, C> From<F> for SubmittedTxHandler<F, C>
68-
where
69-
F: Fn(C, SubmittedTx) -> WorkerResult<Ack> + 'static,
70-
C: TryFrom<wit::Config>,
71-
{
72-
fn from(func: F) -> Self {
73-
Self {
74-
func,
75-
phantom: PhantomData,
76-
}
77-
}
78-
}
79-
80-
impl<F, C> Handler for SubmittedTxHandler<F, C>
81-
where
82-
F: Fn(C, SubmittedTx) -> WorkerResult<Ack> + Send + Sync + 'static,
83-
C: TryFrom<wit::Config, Error = balius_sdk::Error> + Send + Sync + 'static,
84-
{
85-
fn handle(
86-
&self,
87-
config: wit::Config,
88-
event: wit::Event,
89-
) -> Result<wit::Response, wit::HandleError> {
90-
let config: C = config.try_into()?;
91-
let event: Params<SubmittedTx> = event.try_into()?;
92-
let response = (self.func)(config, event.0)?;
93-
Ok(response.try_into()?)
94-
}
95-
}
96-
97-
pub trait WorkerExt {
98-
fn with_tx_submitted_handler<C, F>(self, func: F) -> Self
99-
where
100-
C: TryFrom<wit::Config, Error = balius_sdk::Error> + Send + Sync + 'static,
101-
F: Fn(C, SubmittedTx) -> WorkerResult<Ack> + Send + Sync + 'static;
102-
}
103-
104-
impl WorkerExt for Worker {
105-
fn with_tx_submitted_handler<C, F>(self, func: F) -> Self
106-
where
107-
C: TryFrom<wit::Config, Error = balius_sdk::Error> + Send + Sync + 'static,
108-
F: Fn(C, SubmittedTx) -> WorkerResult<Ack> + Send + Sync + 'static,
109-
{
110-
self.with_request_handler("__tx_submitted", SubmittedTxHandler::from(func))
111-
}
112-
}
113-
114-
pub mod kv {
115-
use balius_sdk::{wit::balius::app::kv, WorkerResult};
116-
use serde::{Deserialize, Serialize};
117-
118-
pub fn get<D: for<'a> Deserialize<'a>>(key: &str) -> WorkerResult<Option<D>> {
119-
match kv::get_value(key) {
120-
Ok(bytes) => Ok(Some(serde_json::from_slice(&bytes)?)),
121-
Err(kv::KvError::NotFound(_)) => Ok(None),
122-
Err(err) => Err(err.into()),
123-
}
124-
}
125-
126-
pub fn set<S: Serialize>(key: &str, value: &S) -> WorkerResult<()> {
127-
kv::set_value(key, &serde_json::to_vec(value)?)?;
128-
Ok(())
129-
}
130-
}
131-
132-
pub trait EventData: Serialize {
133-
fn signature(&self) -> String;
134-
}
135-
136-
#[derive(Serialize, Deserialize)]
137-
pub struct Event {
138-
pub block_hash: Vec<u8>,
139-
pub tx_hash: Vec<u8>,
140-
pub signature: String,
141-
pub data: serde_json::Value,
142-
}
143-
144-
impl Event {
145-
pub fn new<D, E: EventData>(utxo: &Utxo<D>, data: &E) -> WorkerResult<Self> {
146-
Ok(Self {
147-
block_hash: utxo.block_hash.clone(),
148-
tx_hash: utxo.tx_hash.clone(),
149-
signature: data.signature(),
150-
data: serde_json::to_value(data)?,
151-
})
152-
}
153-
}
154-
155-
pub fn emit_events(events: Vec<Event>) -> WorkerResult<()> {
156-
if events.is_empty() {
157-
return Ok(());
158-
}
159-
160-
let mut block_events: HashMap<String, Vec<Event>> = HashMap::new();
161-
for event in events {
162-
let block_hash = hex::encode(&event.block_hash);
163-
block_events.entry(block_hash).or_default().push(event);
164-
}
165-
166-
for (block, mut events) in block_events {
167-
let events_key = format!("__events_{block}");
168-
let mut all_events: Vec<Event> = kv::get(&events_key)?.unwrap_or_default();
169-
all_events.append(&mut events);
170-
kv::set(&events_key, &all_events)?;
171-
}
172-
173-
Ok(())
174-
}
1+
mod events;
2+
pub mod kv;
3+
mod logic;
4+
mod monitor;
5+
mod worker;
6+
7+
pub use events::*;
8+
pub use logic::*;
9+
pub use monitor::*;
10+
pub use worker::*;

firefly-balius/src/logic.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use balius_sdk::txbuilder::{
2+
primitives::TransactionInput, BuildContext, BuildError, InputExpr, UtxoSource,
3+
};
4+
5+
pub struct CoinSelectionInput(pub UtxoSource, pub u64);
6+
7+
// TODO: this is a naive approach to coin selection,
8+
// balius can probably help with a better one
9+
impl InputExpr for CoinSelectionInput {
10+
fn eval(&self, ctx: &BuildContext) -> Result<Vec<TransactionInput>, BuildError> {
11+
let utxos = self.0.resolve(ctx)?;
12+
// If we know the fee, add it to the target amount.
13+
// If not, overestimate the fee so we pick at least as many TXOs as needed.
14+
let target_lovelace = self.1
15+
+ if ctx.estimated_fee == 0 {
16+
2_000_000
17+
} else {
18+
ctx.estimated_fee
19+
};
20+
21+
let mut inputs = vec![];
22+
let mut lovelace_so_far = 0;
23+
let mut pairs: Vec<_> = utxos.iter().collect();
24+
pairs.sort_by_key(|(ref_, _)| (ref_.hash, ref_.index));
25+
for (ref_, txo) in pairs {
26+
let coin = txo.value().coin();
27+
if coin == 0 {
28+
continue;
29+
}
30+
inputs.push(TransactionInput {
31+
transaction_id: ref_.hash,
32+
index: ref_.index,
33+
});
34+
lovelace_so_far += coin;
35+
if lovelace_so_far >= target_lovelace {
36+
break;
37+
}
38+
}
39+
if lovelace_so_far >= target_lovelace {
40+
Ok(inputs)
41+
} else {
42+
Err(BuildError::OutputsTooHigh)
43+
}
44+
}
45+
}

0 commit comments

Comments
 (0)