diff --git a/examples/call-neovm/src/lib.rs b/examples/call-neovm/src/lib.rs index 4f52f8f..ec5ff4d 100644 --- a/examples/call-neovm/src/lib.rs +++ b/examples/call-neovm/src/lib.rs @@ -1,7 +1,7 @@ #![feature(proc_macro_hygiene)] #![no_std] extern crate ontio_std as ostd; -use ostd::abi::{Sink, Source, VmValueParser}; +use ostd::abi::{Sink, Source, VmValueBuilder, VmValueParser}; use ostd::contract::neo; use ostd::prelude::*; use ostd::runtime; @@ -53,7 +53,13 @@ pub fn invoke() { } b"balanceOf" => { let addr: Address = source.read().unwrap(); - let res = neo::call_contract(&NEO_CONTRACT_ADDR, ("balanceOf", addr)); + let mut builder = VmValueBuilder::new(); + builder.string("balanceOf"); + let mut nested = builder.list(); + nested.address(&addr); + nested.finish(); + + let res = runtime::call_contract(&NEO_CONTRACT_ADDR, &builder.bytes()); let mut parser = VmValueParser::new(&res); let r = parser.bytearray().unwrap_or(b"0"); sink.write(u128_from_neo_bytes(r)); diff --git a/ontio-std/Cargo.toml b/ontio-std/Cargo.toml index 8d9b32f..3d2aece 100644 --- a/ontio-std/Cargo.toml +++ b/ontio-std/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ontio-std" -version = "0.3.0" +version = "0.4.0" authors = ["laizy "] edition = "2018" license = "Apache-2.0/MIT" diff --git a/ontio-std/src/abi/event_builder.rs b/ontio-std/src/abi/event_builder.rs index de10d97..d8ca5a5 100644 --- a/ontio-std/src/abi/event_builder.rs +++ b/ontio-std/src/abi/event_builder.rs @@ -118,9 +118,9 @@ impl EventBuilder { } } -pub(crate) struct VmValueBuilderCommon { +pub struct VmValueBuilderCommon { pub(crate) sink: Sink, - num_entry: u32, + pub(crate) num_entry: u32, } impl VmValueBuilderCommon { @@ -128,6 +128,7 @@ impl VmValueBuilderCommon { let sink = Sink::new(12); Self { sink, num_entry: 0u32 } } + pub fn string(&mut self, method: &str) { self.sink.write_byte(TYPE_STRING); self.sink.write_u32(method.len() as u32); diff --git a/ontio-std/src/abi/vm_value_builder.rs b/ontio-std/src/abi/vm_value_builder.rs index e17a84d..26b61e0 100644 --- a/ontio-std/src/abi/vm_value_builder.rs +++ b/ontio-std/src/abi/vm_value_builder.rs @@ -4,7 +4,9 @@ use super::event_builder::{ use super::Error; use super::Source; use super::{VmValueBuilderCommon, VmValueDecoder, VmValueEncoder}; +use crate::abi::event_builder::TYPE_LIST; use crate::prelude::*; +use core::ops::{Deref, DerefMut}; pub struct VmValueBuilder { pub(crate) common: VmValueBuilderCommon, @@ -16,11 +18,40 @@ impl Default for VmValueBuilder { } } +pub struct NestedVmValueBuilder<'a> { + origin: &'a mut VmValueBuilder, + current: VmValueBuilderCommon, +} + +impl<'a> NestedVmValueBuilder<'_> { + pub fn finish(self) { + let mut buf = self.current.sink.into(); + buf[1..5].copy_from_slice(&self.current.num_entry.to_le_bytes()); + self.origin.common.sink.write_bytes(&buf); + } +} + +impl<'a> Deref for NestedVmValueBuilder<'a> { + type Target = VmValueBuilderCommon; + + fn deref(&self) -> &Self::Target { + &self.current + } +} + +impl<'a> DerefMut for NestedVmValueBuilder<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.current + } +} + impl VmValueBuilder { pub fn new() -> Self { let common = VmValueBuilderCommon::new(); let mut builder = VmValueBuilder { common }; - builder.common.sink.write_byte(0u8); + builder.common.sink.write_byte(0u8); // verison + builder.common.sink.write_byte(TYPE_LIST); // list type + builder.common.sink.write_u32(builder.common.num_entry); // occupy length builder } @@ -44,6 +75,15 @@ impl VmValueBuilder { self.common.number(amount); } + pub fn list(&mut self) -> NestedVmValueBuilder { + let mut nested = VmValueBuilderCommon::new(); + nested.sink.write_byte(TYPE_LIST); // list type + nested.sink.write_u32(0); // occupy length + self.common.num_entry += 1; + + NestedVmValueBuilder { origin: self, current: nested } + } + pub fn bool(&mut self, b: bool) { self.common.bool(b); } @@ -53,7 +93,10 @@ impl VmValueBuilder { } pub fn bytes(self) -> Vec { - self.common.sink.into() + let num_entry = self.common.num_entry; + let mut buf = self.common.sink.into(); + buf[2..6].copy_from_slice(&num_entry.to_le_bytes()); + buf } } @@ -109,17 +152,11 @@ impl<'a> VmValueParser<'a> { pub fn bool(&mut self) -> Result { let ty = self.source.read_byte()?; - if ty == TYPE_BOOL { - return self.source.read_bool(); - } else if ty == TYPE_INT { - let res = self.source.read_u128()?; - if res != 0 { - return Ok(true); - } else { - return Ok(false); - } + match ty { + TYPE_BOOL => self.source.read_bool(), + TYPE_INT => Ok(self.source.read_u128()? != 0), + _ => Err(Error::TypeInconsistency), } - Err(Error::TypeInconsistency) } pub fn h256(&mut self) -> Result<&'a H256, Error> { @@ -130,3 +167,34 @@ impl<'a> VmValueParser<'a> { self.source.read_h256() } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::abi::Sink; + + #[test] + fn test_builder() { + let mut builder = VmValueBuilder::new(); + let addr = Address::default(); + builder.string("balanceOf"); + let mut nested = builder.list(); + nested.address(&addr); + nested.finish(); + + let mut sink = Sink::new(10); + sink.write_byte(0); //version + sink.write_byte(TYPE_LIST); // type + sink.write_u32(2); // two param + sink.write_byte(TYPE_STRING); // first param + let param = "balanceOf"; + sink.write_u32(param.len() as u32); + sink.write_bytes(param.as_bytes()); + + sink.write_byte(TYPE_LIST); // second param + sink.write_u32(1); + sink.write_byte(TYPE_ADDRESS); // first param + sink.write(&addr); + assert_eq!(builder.bytes(), sink.into()); + } +}