use super::*;
use console::program::FinalizeType;
impl<N: Network> RegistersTrait<N> for FinalizeRegisters<N> {
fn load(&self, stack: &impl StackTrait<N>, operand: &Operand<N>) -> Result<Value<N>> {
let register = match operand {
Operand::Literal(literal) => return Ok(Value::Plaintext(Plaintext::from(literal))),
Operand::Register(register) => register,
Operand::ProgramID(program_id) => {
return Ok(Value::Plaintext(Plaintext::from(Literal::Address(program_id.to_address()?))));
}
Operand::Signer => bail!("Forbidden operation: Cannot use 'self.signer' in 'finalize'"),
Operand::Caller => bail!("Forbidden operation: Cannot use 'self.caller' in 'finalize'"),
Operand::BlockHeight => {
return Ok(Value::Plaintext(Plaintext::from(Literal::U32(U32::new(self.state.block_height())))));
}
Operand::NetworkID => {
return Ok(Value::Plaintext(Plaintext::from(Literal::U16(U16::new(N::ID)))));
}
Operand::Checksum(program_id) => {
let checksum = match program_id {
Some(program_id) => *stack.get_external_stack(program_id)?.program_checksum(),
None => *stack.program_checksum(),
};
return Ok(Value::Plaintext(Plaintext::from(checksum)));
}
Operand::Edition(program_id) => {
let edition = match program_id {
Some(program_id) => stack.get_external_stack(program_id)?.program_edition(),
None => stack.program_edition(),
};
return Ok(Value::Plaintext(Plaintext::from(Literal::U16(edition))));
}
Operand::ProgramOwner(program_id) => {
let program_owner = match program_id {
Some(program_id) => *stack.get_external_stack(program_id)?.program_owner(),
None => *stack.program_owner(),
};
let address = match program_owner {
Some(address) => address,
None => bail!("The program owner does not exist for the program '{}'.", stack.program_id()),
};
return Ok(Value::Plaintext(Plaintext::from(Literal::Address(address))));
}
};
let value = self.registers.get(®ister.locator()).ok_or_else(|| anyhow!("'{register}' does not exist"))?;
let value = match register {
Register::Locator(..) => value.clone(),
Register::Access(_, path) => value.find(path)?,
};
match (self.finalize_types.get_type(stack, register), &value) {
(Ok(FinalizeType::Plaintext(plaintext_type)), Value::Plaintext(plaintext_value)) => {
stack.matches_plaintext(plaintext_value, &plaintext_type)?
}
(Ok(FinalizeType::Future(locator)), Value::Future(future)) => stack.matches_future(future, &locator)?,
(Ok(finalize_type), stack_value) => bail!(
"Attempted to load a '{stack_value}' value from a register '{register}' of type '{finalize_type}' in a finalize scope",
),
(Err(error), _) => bail!("Register '{register}' is not a member of the function: {error}"),
};
Ok(value)
}
fn store(&mut self, stack: &impl StackTrait<N>, register: &Register<N>, stack_value: Value<N>) -> Result<()> {
match (register, stack_value) {
(Register::Locator(locator), stack_value) => {
match self.last_register {
None => ensure!(*locator == 0, "Out-of-order write operation at '{register}'"),
Some(last) => ensure!(*locator > last, "Out-of-order write operation at '{register}'"),
};
ensure!(!self.registers.contains_key(locator), "Cannot write to occupied register '{register}'");
match (self.finalize_types.get_type(stack, register), &stack_value) {
(Ok(FinalizeType::Plaintext(plaintext_type)), Value::Plaintext(plaintext_value)) => {
stack.matches_plaintext(plaintext_value, &plaintext_type)?
}
(Ok(FinalizeType::Future(locator)), Value::Future(future)) => {
stack.matches_future(future, &locator)?
}
(Ok(finalize_type), stack_value) => bail!(
"Attempted to store a '{stack_value}' value in a register '{register}' of type '{finalize_type}' in a finalize scope",
),
(Err(error), _) => bail!("Register '{register}' is missing a type definition: {error}"),
};
match self.registers.insert(*locator, stack_value) {
Some(..) => bail!("Attempted to write to register '{register}' again"),
None => {
self.last_register = Some(*locator);
Ok(())
}
}
}
(Register::Access(..), _) => bail!("Cannot store to a register access: '{register}'"),
}
}
}