Make conditions explicit in races
And boot recursive spending plans. That path required heap allocations. Since we don't have a need for this generality right now, reduce the language to the smallest one that can pass our test suite.
This commit is contained in:
@ -5,7 +5,7 @@
|
|||||||
use hash::Hash;
|
use hash::Hash;
|
||||||
use entry::Entry;
|
use entry::Entry;
|
||||||
use event::Event;
|
use event::Event;
|
||||||
use plan::{Action, Plan};
|
use plan::{Action, Plan, PlanEvent};
|
||||||
use transaction::Transaction;
|
use transaction::Transaction;
|
||||||
use signature::{KeyPair, PublicKey, Signature};
|
use signature::{KeyPair, PublicKey, Signature};
|
||||||
use mint::Mint;
|
use mint::Mint;
|
||||||
@ -141,7 +141,7 @@ impl Accountant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut plan = tr.plan.clone();
|
let mut plan = tr.plan.clone();
|
||||||
let actionable = plan.process_verified_timestamp(self.last_time);
|
let actionable = plan.process_event(PlanEvent::Timestamp(self.last_time));
|
||||||
|
|
||||||
if !actionable {
|
if !actionable {
|
||||||
self.pending.insert(tr.sig, plan);
|
self.pending.insert(tr.sig, plan);
|
||||||
@ -154,7 +154,7 @@ impl Accountant {
|
|||||||
|
|
||||||
fn process_verified_sig(&mut self, from: PublicKey, tx_sig: Signature) -> Result<()> {
|
fn process_verified_sig(&mut self, from: PublicKey, tx_sig: Signature) -> Result<()> {
|
||||||
let actionable = if let Some(plan) = self.pending.get_mut(&tx_sig) {
|
let actionable = if let Some(plan) = self.pending.get_mut(&tx_sig) {
|
||||||
plan.process_verified_sig(from)
|
plan.process_event(PlanEvent::Signature(from))
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
@ -186,7 +186,7 @@ impl Accountant {
|
|||||||
// Check to see if any timelocked transactions can be completed.
|
// Check to see if any timelocked transactions can be completed.
|
||||||
let mut completed = vec![];
|
let mut completed = vec![];
|
||||||
for (key, plan) in &mut self.pending {
|
for (key, plan) in &mut self.pending {
|
||||||
if plan.process_verified_timestamp(self.last_time) {
|
if plan.process_event(PlanEvent::Timestamp(self.last_time)) {
|
||||||
completed.push(key.clone());
|
completed.push(key.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
102
src/plan.rs
102
src/plan.rs
@ -10,6 +10,23 @@ pub enum Condition {
|
|||||||
Signature(PublicKey),
|
Signature(PublicKey),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum PlanEvent {
|
||||||
|
Timestamp(DateTime<Utc>),
|
||||||
|
Signature(PublicKey),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Condition {
|
||||||
|
pub fn is_satisfied(&self, event: &PlanEvent) -> bool {
|
||||||
|
match (self, event) {
|
||||||
|
(&Condition::Signature(ref pubkey), &PlanEvent::Signature(ref from)) => pubkey == from,
|
||||||
|
(&Condition::Timestamp(ref dt), &PlanEvent::Timestamp(ref last_time)) => {
|
||||||
|
dt <= last_time
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
Pay(Payment),
|
Pay(Payment),
|
||||||
@ -18,7 +35,7 @@ pub enum Action {
|
|||||||
impl Action {
|
impl Action {
|
||||||
pub fn spendable(&self) -> i64 {
|
pub fn spendable(&self) -> i64 {
|
||||||
match *self {
|
match *self {
|
||||||
Action::Pay(ref payment) => payment.asset.clone(),
|
Action::Pay(ref payment) => payment.asset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -32,90 +49,41 @@ pub struct Payment {
|
|||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum Plan {
|
pub enum Plan {
|
||||||
Action(Action),
|
Action(Action),
|
||||||
After(Condition, Box<Plan>),
|
After(Condition, Action),
|
||||||
Race(Box<Plan>, Box<Plan>),
|
Race((Condition, Action), (Condition, Action)),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Plan {
|
impl Plan {
|
||||||
pub fn verify(&self, spendable_assets: i64) -> bool {
|
pub fn verify(&self, spendable_assets: i64) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
Plan::Action(ref action) => action.spendable() == spendable_assets,
|
Plan::Action(ref action) => action.spendable() == spendable_assets,
|
||||||
Plan::Race(ref plan_a, ref plan_b) => {
|
Plan::After(_, ref action) => action.spendable() == spendable_assets,
|
||||||
plan_a.verify(spendable_assets) && plan_b.verify(spendable_assets)
|
Plan::Race(ref a, ref b) => {
|
||||||
|
a.1.spendable() == spendable_assets && b.1.spendable() == spendable_assets
|
||||||
}
|
}
|
||||||
Plan::After(_, ref plan) => plan.verify(spendable_assets),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_race(&mut self) -> bool {
|
pub fn process_event(&mut self, event: PlanEvent) -> bool {
|
||||||
let new_plan = if let Plan::Race(ref a, ref b) = *self {
|
let mut new_action = None;
|
||||||
if let Plan::Action(_) = **a {
|
|
||||||
Some((**a).clone())
|
|
||||||
} else if let Plan::Action(_) = **b {
|
|
||||||
Some((**b).clone())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(plan) = new_plan {
|
|
||||||
mem::replace(self, plan);
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn process_verified_sig(&mut self, from: PublicKey) -> bool {
|
|
||||||
let mut new_plan = None;
|
|
||||||
match *self {
|
match *self {
|
||||||
Plan::Action(_) => return true,
|
Plan::Action(_) => return true,
|
||||||
Plan::Race(ref mut plan_a, ref mut plan_b) => {
|
Plan::After(ref cond, ref action) => {
|
||||||
plan_a.process_verified_sig(from);
|
if cond.is_satisfied(&event) {
|
||||||
plan_b.process_verified_sig(from);
|
new_action = Some(action.clone());
|
||||||
}
|
|
||||||
Plan::After(Condition::Signature(pubkey), ref plan) => {
|
|
||||||
if from == pubkey {
|
|
||||||
new_plan = Some((**plan).clone());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
Plan::Race(ref a, ref b) => {
|
||||||
}
|
if a.0.is_satisfied(&event) {
|
||||||
if self.run_race() {
|
new_action = Some(a.1.clone());
|
||||||
return true;
|
} else if b.0.is_satisfied(&event) {
|
||||||
}
|
new_action = Some(b.1.clone());
|
||||||
|
|
||||||
if let Some(plan) = new_plan {
|
|
||||||
mem::replace(self, plan);
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn process_verified_timestamp(&mut self, last_time: DateTime<Utc>) -> bool {
|
|
||||||
let mut new_plan = None;
|
|
||||||
match *self {
|
|
||||||
Plan::Action(_) => return true,
|
|
||||||
Plan::Race(ref mut plan_a, ref mut plan_b) => {
|
|
||||||
plan_a.process_verified_timestamp(last_time);
|
|
||||||
plan_b.process_verified_timestamp(last_time);
|
|
||||||
}
|
|
||||||
Plan::After(Condition::Timestamp(dt), ref plan) => {
|
|
||||||
if dt <= last_time {
|
|
||||||
new_plan = Some((**plan).clone());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
if self.run_race() {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(plan) = new_plan {
|
if let Some(action) = new_action {
|
||||||
mem::replace(self, plan);
|
mem::replace(self, Plan::Action(action));
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
@ -18,10 +18,7 @@ pub struct Transaction {
|
|||||||
impl Transaction {
|
impl Transaction {
|
||||||
pub fn new(from_keypair: &KeyPair, to: PublicKey, asset: i64, last_id: Hash) -> Self {
|
pub fn new(from_keypair: &KeyPair, to: PublicKey, asset: i64, last_id: Hash) -> Self {
|
||||||
let from = from_keypair.pubkey();
|
let from = from_keypair.pubkey();
|
||||||
let plan = Plan::Action(Action::Pay(Payment {
|
let plan = Plan::Action(Action::Pay(Payment { asset, to }));
|
||||||
asset: asset.clone(),
|
|
||||||
to,
|
|
||||||
}));
|
|
||||||
let mut tr = Transaction {
|
let mut tr = Transaction {
|
||||||
from,
|
from,
|
||||||
plan,
|
plan,
|
||||||
@ -42,20 +39,11 @@ impl Transaction {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
let from = from_keypair.pubkey();
|
let from = from_keypair.pubkey();
|
||||||
let plan = Plan::Race(
|
let plan = Plan::Race(
|
||||||
Box::new(Plan::After(
|
(Condition::Timestamp(dt), Action::Pay(Payment { asset, to })),
|
||||||
Condition::Timestamp(dt),
|
(
|
||||||
Box::new(Plan::Action(Action::Pay(Payment {
|
|
||||||
asset: asset.clone(),
|
|
||||||
to,
|
|
||||||
}))),
|
|
||||||
)),
|
|
||||||
Box::new(Plan::After(
|
|
||||||
Condition::Signature(from),
|
Condition::Signature(from),
|
||||||
Box::new(Plan::Action(Action::Pay(Payment {
|
Action::Pay(Payment { asset, to: from }),
|
||||||
asset: asset.clone(),
|
),
|
||||||
to: from,
|
|
||||||
}))),
|
|
||||||
)),
|
|
||||||
);
|
);
|
||||||
let mut tr = Transaction {
|
let mut tr = Transaction {
|
||||||
from,
|
from,
|
||||||
|
Reference in New Issue
Block a user