-
Notifications
You must be signed in to change notification settings - Fork 677
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
Code Review: Smart Contract VM 02/13/19 #921
Conversation
…paration for creating contract contexts-- a transaction should _never_ be able to modify a contract's global context.
src/vm/errors.rs
Outdated
BadSymbolicRepresentation(String), | ||
ReservedName(String), | ||
InterpreterError(String), | ||
MultiplyDefined(String) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"MultiplyDefined"? As in, defined multiple times, or something to do with the multiplication operator?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, it's an error when you use the same variable name multiple times in a variable declaration like, the function definition:
(define (foo a a) (+ a a))
I can rename it to VariableDefinedMultipleTimes
src/vm/types.rs
Outdated
List(Vec<Value>, TypeSignature), | ||
Principal(u8, Vec<u8>), // a principal is a version byte + hash160 (20 bytes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can enforce this in the type system by using [u8; 20]
instead of Vec<u8>
src/vm/types.rs
Outdated
let mut value_size: i128 = 0; | ||
for (name, type_signature) in self.type_map.iter() { | ||
// we only accept ascii names, so 1 char = 1 byte. | ||
name_size = name_size.checked_add(name.len() as i128).unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For these unwrap()
s, can you add an error message?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, how certain are we that these unwrap()
s never occur?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure -- will add an error message.
These panics should never occur, since the composite values of the tuple should be smaller than MAX_VALUE_SIZE (much smaller than i128::max bytes) and combining them until the tuple is too large would require an extraordinarily large program. However, since the max value size check for tuple (and list) types occurs using the size()
method, it's theoretically possible. So I'll change these to raise a ValueTooLarge error.
// e.g.: (list "abcd" "abc") will currently error because one etry is | ||
// if type (buffer 4) and the other is of type (buffer 3) | ||
// my feeling is that this should probably be allowed, and the resulting | ||
// type should be (list 2 (buffer 4)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, just as long as we can make it clear somehow that (list "abcdefghijk" "abc")
costs as much to process as (list "abcdefghijk" "\x00\x00\x00\x00\x00\x00\x00\x00\x00abc")
. We'd also want to be careful about how we "expand" shorter buffer items -- do we left-pad them with 0?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep -- we'd need to make this clear. I think the behavior we want is that for any functions which accepts two buffers, to treat the smaller buffer as left padded with zeros. currently we don't have any buffer functions (except eq?
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do you want to handle eq?
for buffers that get implicitly left-padded with zeros? I don't think \x00abc
and abc
are necessarily equal. Maybe the buffer type should include a length
field internally to avoid this problem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I was just going to comment on this. Those shouldn't be equal. Buffers should have a length, which they do currently (via their vec.len()
), but the Buffer type has a maximum length, which is a little silly for a buffer's runtime type (because its length is always equal to its maximum length), but for declared types like public function inputs and datamap keys, values, it makes sense, because the maximum length determines whether or not a given runtime value would be admissable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(this contradicts my previous response up there --- I don't think we should be automatically extending buffers. if we decide to include buffer functions like strncat
, they should specify their padding behavior, if they have any)
src/vm/parser.rs
Outdated
// lazy_static (or just hand implementing that), and I'm not convinced | ||
// it's worth either (1) an extern macro, or (2) the complexity of hand implementing. | ||
let lex_matchers: &[LexMatcher] = &[ | ||
LexMatcher::new(r##""(?P<value>((\\")|([[:ascii:]&&[^"\n\r\t]]))*)""##, TokenType::StringLiteral), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is :ascii:
here? Is it printable ASCII characters? Also, can we have a lexer test below for ensuring that a code snippit with non-printable characters does not parse?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, the str
type is a unicode string slice. We'll want the lexer to reject non-ASCII strings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah -- that :ascii:
class should actually be :print:
for printable ascii characters.
But this lexer will reject non-ASCII strings. None of these matchers will match a non-ascii character, which will cause the lexer to fail (if the lexer cannot process a given character, it exhaust all the matches and returns a ParseError)
… Value to derive. remove now uneccessary Hash traits.
Okay -- I pushed changes that addressed all of those issues.
|
Thanks! As soon as CircleCI finishes, please go ahead and merge to |
Thanks for the review! The Circle CI tests look like they've finished successfully (https://circleci.com/gh/blockstack/blockstack-core/1716), so I'll go ahead and merge (Circle github notifications/commit check updates appear to currently be broken). |
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
This PR adds the following:
(define-public ...)
function for specifying the public functions in a contract.(list 3 (buffer 5))
)This PR also reimplements the lexer from #908 so that it is a much more standard lexer (and the lexer itself handles literals).
This PR addresses:
#911
#913 -- though this will need to be revisited during the course of the implementation
#914
#915
#917
#918