-
-
Notifications
You must be signed in to change notification settings - Fork 81
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Contract API #9
Comments
Couple issues:
An option here is to force the contract to return serialized state after computation and this would be handled by the node runtime.
|
My thought was that the If wasm functions can't be passed mutable parameters then
This will be handled by the |
Suggestion for making this more idiomatic: type ContractKeyResult<T> = Result<T, ContractKeyError>;
struct ContractKeyError {
/// original PUT value
value: Vec<u8>,
kind: ErrorKind
}
enum ErrorKind {
...
}
trait ContractKey {
/// Determine whether this value is valid for this contract
fn validate_value(value : &[u8]) -> bool;
/// Determine whether this value is a valid update for this contract. If it is, return the modified value,
/// else return error and the original value.
fn update_value(value: Vec<u8>, value_update: &[u8]) -> ContractKeyResult<Vec<u8>>;
/// Obtain any other related contracts for this value update. Typically used to ensure
/// update has been fully propagated.
fn related_contracts(value_update : &[u8]) -> Vec<ContractKey>;
/// Extract some data from the value and return it.
///
/// eg. `extractor` might contain a byte range, which will be extracted
/// from the value and returned.
fn extract(extractor : &[u8], value: &[u8]) -> Vec<u8>;
} |
Wanted to get a few thoughts down:
There are three possibilities for a
Note: The current Questions:
|
Currently Regarding your question, we don't know if a value update has been already seen right now from outside the contract, if so this information should be communicated or computed somehow (hashing the value and if it success it should show in the commit log). I see pros and cons here, it could potentially remove noise from the network, but on the other side add to the compute/memory footprint of the node... Although this would be highly specific to the contract (it may very well cheaper to avoid running the contract again with a value that already was observer instead of blindly broadcasting it). My first initial intuition is that is worth trying to deduplicate beforehand, but this will be limited and expire since we are not gonna keep an unlimited history of those updates.
Correct. We could consider values like packets sent, specially if we consider that those can be partial (is not strictly required to send the whole value when you are putting, you can send just one "partial" value that then can be ingested by the contract and incorporated). |
I think the main motivation would be that it would allow deduplication of updates without needing to maintain some other record of them.
Agreed, however, if contracts report whether a value has already been applied then it becomes an implicit record of what updates have already been made to the contract. This would allow for update deduplication without the need to maintain an explicit list of which updates we've seen - the contract value is the record.
Is a "partial" value the same as a value_update? The concepts seem very similar. Another question that occurred to me: Should a contract support "merging" two values? The idea would be that let's say a value - V1 - contains updates U1, U3, and U4, but another node had a value V2 which contained updates U1, U2, and U3. If these nodes were to somehow discover that they had different values for the same contract, seems like it would be useful for them to combine their knowledge, which would mean "merging" their values. On the positive side, this seems like it would help ensure that updates reach the peers that need them. On the negative side, hopefully the network will be very good at getting updates where they need to be - so this situation may not happen frequently enough to matter. |
Another thought, perhaps instead of: fn related_contracts(value_update : &[u8]) -> Vec<ContractKey>; We modify fn update_value(value: Vec<u8>, value_update: &[u8], store : &mut Store) -> ContractKeyResult<Vec<u8>>; Where impl Store {
fn update_value(&mut self, contract : &Contract, value : &Vec<u8>);
} |
struct TwitterValue {
tweets : Vec<Tweet>, // Stores the most recent 5 tweets for this contract
}
struct TwitterUpdate {
tweets : Vec<Tweet>, // Stores the most recent 5 tweets for this contract
}
fn update_value(value : TwitterValue, update : TwitterUpdate) -> TwitterValue {
let newValueTweets = (value.tweets + update.tweets).sort().take_last_n(5);
TwitterValue { tweets : newValueTweets}
}
struct TweetExtractor {
get_tweets : Vec<TweetID>,
}
fn extract(query : &[u8], value : &TwitterValue) -> ExtractedTweet {
ExtractedTweets {
tweets = value.tweets.filter(query),
}
} Question: Combine TwitterValue and TwitterUpdate, so every TwitterUpdate is a TwitterValue, and multiple values can be "merged" to create a new TwitterValue - meeting the criteria that values are commutative - doesn't matter what order they're merged it. |
Rewrote issue based on discussion. |
Removed the get function as we're dropping the |
Last proposal: trait Contract {
// Validation functions
fn validate_state(parameters : &Parameters, state : &State) -> bool;
fn validate_message(parameters : &Parameters, message : &Message) -> bool;
/// if the state has been changed persist the changes
fn update_state(parameters : &Parameters, state : &mut State, message : &Message) -> bool;
/// relay this message to each of the contract + parameters tuple given back by the function
fn related_contracts(parameters : &Parameters, message : &Message) -> Vec<(Contract, Parameters)>;
// node layer:
// These functions facilitate more efficient synchronization of state between peers
fn summarize_state(parameters : &Parameters, state : &State) -> StateSummary;
fn get_state_delta(parameters : &Parameters, state : &State, delta_to : &StateSummary) -> StateDelta;
fn apply_state_delta(parameters : &Parameters, state : &mut State, delta : &StateDelta) -> bool;
// appliction layer:
fn request(parameters : &Parameters, query : &Query) -> Result<Response, Error>;
} |
@sanity I kind of forgot why we hav a Also maybe a suggestion, we can remove /// if the state has been changed persist the changes
fn update_state(parameters : &Parameters, state : &mut State, message : &Message) -> Result<bool, _>;
The idea here would be that you validate if the message is valid (if is invalid you return Err(_)), and if is valid you attempt to update (in case it was duplicate you would return Ok(false), otherwise Ok(true)). It's probably more optimal for many contracts that first validating and then updating and you can do it all in the same pass. |
@iduartgomez I think the motivation for Re: combining the |
Contract functions: Validate Statefn validate_state() -> bool; Memory layout:
Returns Validate Deltafn validate_delta() -> bool; Memory layout:
Returns Update Statefn update_state() -> UpdateResult;
enum UpdateResult {
VALID_UPDATED, VALID_NO_CHANGE, INVALID,
} Memory layout:
The State should be updated to incorporate the delta if valid. Note that the delta can be appended to the state without Summarize Statefn summarize_state(); Memory layout:
The state summary should be placed after the State by the function, preceded by its length in bytes in the usual manner. Get State Deltafn get_state_delta(); Memory layout:
The state delta should be placed after the state summary, preceded by its length in the usual way. Possible additional functionsfn related_contracts(); Questions
|
I've rewritten the original issue description with the latest proposal. |
I think the first iteration of the contract API is complete and we can refine it further with additional issues like: |
Note that the
Related
struct implies the following approach to generating a contract hash:The reason is so that a
contract_hash
can be created with only a hash of thecontract_wasm
, not the entirecontract_wasm
. This should reduce contract sizes.The text was updated successfully, but these errors were encountered: