/* This file is part of DarkFi (https://dark.fi) * * Copyright (C) 2020-2022 Dyne.org foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ use darkfi_sdk::{ crypto::ContractId, db::{db_get, db_init, db_lookup, db_set}, define_contract, error::ContractResult, msg, pasta::pallas, tx::FuncCall, util::{set_return_data, put_object_bytes, get_object_bytes, get_object_size}, }; use darkfi_serial::{deserialize, serialize, Encodable, SerialDecodable, SerialEncodable, WriteExt, ReadExt}; /// Available functions for this contract. /// We identify them with the first byte passed in through the payload. #[repr(u8)] pub enum Function { Foo = 0x00, Bar = 0x01, } impl From for Function { fn from(b: u8) -> Self { match b { 0x00 => Self::Foo, 0x01 => Self::Bar, _ => panic!("Invalid function ID: {:#04x?}", b), } } } // An example of deserializing the payload into a struct #[derive(SerialEncodable, SerialDecodable)] pub struct FooCallData { pub a: u64, pub b: u64, } impl FooCallData { //fn zk_public_values(&self) -> Vec<(String, Vec)>; //fn get_metadata(&self) { //} } #[derive(SerialEncodable, SerialDecodable)] pub struct BarArgs { pub x: u32, } #[derive(SerialEncodable, SerialDecodable)] pub struct FooUpdate { pub name: String, pub age: u32, } define_contract!( init: init_contract, exec: process_instruction, apply: process_update, metadata: get_metadata ); fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult { msg!("wakeup wagies!"); // Initialize a state tree. db_init will fail if the tree already exists. // Otherwise, it will return a `DbHandle` that can be used further on. // TODO: If the deploy execution fails, whatever is initialized with db_init // should be deleted from sled afterwards. There's no way to create a // tree but only apply the creation when we're done, so db_init creates // it and upon failure it should delete it let wagies_handle = db_init(cid, "wagies")?; db_set(wagies_handle, &serialize(&"jason_gulag".to_string()), &serialize(&110))?; Ok(()) } fn get_metadata(_cid: ContractId, ix: &[u8]) -> ContractResult { match Function::from(ix[0]) { Function::Foo => { let tx_data = &ix[1..]; // ... let (func_call_index, func_calls): (u32, Vec) = deserialize(tx_data)?; let _call_data: FooCallData = deserialize(&func_calls[func_call_index as usize].call_data)?; let zk_public_values = vec![ ( "DaoProposeInput".to_string(), vec![pallas::Base::from(110), pallas::Base::from(4)], ), ("DaoProposeInput".to_string(), vec![pallas::Base::from(7), pallas::Base::from(4)]), ( "DaoProposeMain".to_string(), vec![ pallas::Base::from(1), pallas::Base::from(3), pallas::Base::from(5), pallas::Base::from(7), ], ), ]; let signature_public_keys: Vec = vec![ //pallas::Point::identity() ]; let mut metadata = Vec::new(); zk_public_values.encode(&mut metadata)?; signature_public_keys.encode(&mut metadata)?; set_return_data(&metadata)?; msg!("metadata returned!"); // Convert call_data to halo2 public inputs // Pass this to the env } Function::Bar => { // ... } } Ok(()) } // This is the main entrypoint function where the payload is fed. // Through here, you can branch out into different functions inside // this library. fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult { msg!("process_instruction():"); msg!(" ix: {:x?}", ix); msg!(" cid: {:x?}", cid); //let bytes = [0xde, 0xad, 0xbe, 0xef]; let bytes = [0x3a, 0x14, 0x15, 0x92, 0x63, 0x35]; let obj = put_object_bytes(&bytes); let obj_size = get_object_size(obj as u32); msg!(" obj_size: {}", obj_size); let mut buf = vec![0u8; obj_size as usize]; get_object_bytes(&mut buf, obj as u32); msg!(" buf (bytes): {:x?}", &buf); match Function::from(ix[0]) { Function::Foo => { let tx_data = &ix[1..]; // ... let (func_call_index, func_calls): (u32, Vec) = deserialize(tx_data)?; let call_data: FooCallData = deserialize(&func_calls[func_call_index as usize].call_data)?; msg!("call_data {{ a: {}, b: {} }}", call_data.a, call_data.b); // ... let update = FooUpdate { name: "john_doe".to_string(), age: 110 }; let mut update_data = vec![Function::Foo as u8]; update_data.extend_from_slice(&serialize(&update)); set_return_data(&update_data)?; msg!("update is set!"); // Example: try to get a value from the db let db_handle = db_lookup(cid, "wagies")?; if let Some(age_data) = db_get(db_handle, &serialize(&"jason_gulag".to_string()))? { let age_data: u32 = deserialize(&age_data)?; msg!("wagie age data: {}", age_data); } else { msg!("didn't find wagie age data"); } } Function::Bar => { //let tx_data = &ix[1..]; // ... //let _args: BarArgs = deserialize(tx_data)?; } } msg!("process_instruction() [END]"); Ok(()) } fn process_update(_cid: ContractId, update_data: &[u8]) -> ContractResult { msg!("Make 1 update!"); match Function::from(update_data[0]) { Function::Foo => { msg!("fooupp"); let update: FooUpdate = deserialize(&update_data[1..])?; // Write the wagie to the db //let tx_handle = db_begin_tx()?; //db_set(tx_handle, &serialize(&update.name), &serialize(&update.age))?; //let db_handle = db_lookup("wagies")?; //db_end_tx(db_handle, tx_handle)?; } Function::Bar => { } } msg!("process_update() finished"); Ok(()) }