Skip to content

Test to make sure that LLLC is compiling all valid opcodes correctly#3002

Merged
axic merged 1 commit intoargotorg:developfrom
jwasinger:lll-opcode-test
Oct 18, 2017
Merged

Test to make sure that LLLC is compiling all valid opcodes correctly#3002
axic merged 1 commit intoargotorg:developfrom
jwasinger:lll-opcode-test

Conversation

@jwasinger
Copy link
Contributor

@jwasinger jwasinger commented Oct 2, 2017

AFAIK SHA3 is the only opcode not currently implemented in LLLC.

Related: ethereum/aleth#4519

};

std::vector<std::string> opcodes_lll {
"{ (STOP) (RETURN 0x0 0x1) }",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return is dead code here after stop

"{ (XOR 0x00 0x00) (RETURN 0x0 0x0) }",
"{ (NOT 0x00) (RETURN 0x0 0x0) }",
"{ (BYTE 0 0x8050201008040201) (RETURN 0x0 0x0) }",
//"{ (SHA3 0x00 0x00) (RETURN 0x0 0x0) }", //SHA3 opcode not implemented
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is called keccak256 and not sha3.

"{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff (return 0x0 0x0)}",
"{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff (return 0x0 0x0)}",
"{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff (return 0x0 0x0)}",
"{ (DUP1 0xff) (return 0x0 0x0)}",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the point of the 0xff parameter for DUPs and SWAPs? They do not take parameters and this case (for some reason) gets compiled as pushes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well to be honest, DUP and SWAP make no sense for the instructional form in LLL.

All these are also available as inline assembly:

(asm 1 2 3 DUP2 SWAP3)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed this in #3005.

"{ (EXTCODECOPY 0x1000000000000000000000000000000000000010 0 0 20) (RETURN 0x0 0x0) }",
"{ (RETURNDATASIZE) (RETURN 0x0 0x0) }",
"{ (RETURNDATACOPY 0x0 0x0 0x0) (RETURN 0x0 0x0) }",
"{ 0x00 (POP 0x00) (RETURN 0x0 0x0) }",
Copy link
Contributor

@axic axic Oct 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be a a push 0, push 0, pop, but not as an instruction as the rest of them.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd argue having POP as a functional instruction is useless given every stray stack argument is popped anyway.

e.g.

(ORIGIN)

and

(POP (ORIGIN))

has the same stack result.

"{ (DELEGATECALL 100000 0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 0 0 0 0) (return 0x0 0x0) }",
"{ (STATICCALL 10000 0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 0 0 0 0) (return 0x0 0x0) }",
"{ (REVERT 0x0 0x0) (return 0x0 0x0)}",
"{ (SELFDESTRUCT (ORIGIN)) }"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If all the others used a PUSH for the argument, perhaps do the same here?

@axic
Copy link
Contributor

axic commented Oct 2, 2017

Some of the instructions are lowercase while others are uppercase. Also having return after every one of them seems not very useful. Any reason for these?


if (!errors.empty()) {
BOOST_FAIL(opcodes_lll[i]);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this part above you could copy the code from test/liblll/ExecutionFramework.h.

std::stringstream ss;

for (size_t i = 0; i < code.size(); i++) {
ss << boost::format("%02x") % (int)code[i];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could just use toHex(code) to achieve the same.

"{ (PC) (RETURN 0x0 0x0) }",
"{ (MSIZE) (RETURN 0x0 0x0) }",
"{ (GAS) (RETURN 0x0 0x0) }",
"{ (JUMPDEST) (RETURN 0x0 0x0) }",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems pointless too, should disable it in the compiler.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed this in #3005.

"{ (RETURN 0x0 0x0) }",
"{ (DELEGATECALL 100000 0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 0 0 0 0) (return 0x0 0x0) }",
"{ (STATICCALL 10000 0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 0 0 0 0) (return 0x0 0x0) }",
"{ (REVERT 0x0 0x0) (return 0x0 0x0)}",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

INVALID is not tested for.

"{ (CALLDATASIZE) (RETURN 0x0 0x0) }",
"{ (CALLDATACOPY 0x0 0x0 0x0) (RETURN 0x0 0x0) }",
"{ (CODESIZE) (RETURN 0x0 0x0) }",
"{ (CODECOPY 0x1 0x0 (CODESIZE)) [[ 0 ]] (MLOAD 0x1) (RETURN 0x0 0x0) }",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why mix the built in notation of sstore with the rest? This code right now reads as

(CODECOPY 0x1 0x0 (CODESIZE))
(SSTORE 0 (MLOAD 0x1))
(RETURN 0x0 0x0)

is that intended?

@jwasinger
Copy link
Contributor Author

jwasinger commented Oct 2, 2017

Thanks for the review. Have a long day of flights today. I will address these points tomorrow.

Copy link
Contributor

@axic axic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should add a second set of tests for using inline assembly, where all the opcodes are available: (asm 1 2 ADD BALANCE SUB)

@jwasinger
Copy link
Contributor Author

jwasinger commented Oct 2, 2017

These were pulled directly from a state test I wrote: https://github.com/ethereum/tests/blob/develop/GeneralStateTests/stTransactionTest/Opcodes_TransactionInit.json .

Makes sense to re-write that as well.

Having two tests (one for good opcodes, one for unused opcodes) is sensible here.

@axic
Copy link
Contributor

axic commented Oct 3, 2017

Needs to be rebased for latest LLL fixes.

@jwasinger
Copy link
Contributor Author

@axic I revised the test simplifying the code, added the use of toHex, rebased off develop.

@axic
Copy link
Contributor

axic commented Oct 4, 2017

Thanks @jwasinger. I think the functional tests were useful too. Not sure which one is used in test generation though.

Also all these should move to test/liblll/Compiler from Parser.

@axic
Copy link
Contributor

axic commented Oct 5, 2017

I am not sure which one is used in ethereum/tests, (asm) blocks or functional instructions? If the latter, having tests for them cannot hurt.

@jwasinger jwasinger force-pushed the lll-opcode-test branch 2 times, most recently from 949bbab to dcb651a Compare October 12, 2017 04:36
@jwasinger
Copy link
Contributor Author

I added a test for functional instructions. I think it should be ready to merge @axic

"{ (asm MSIZE) }",
"{ (asm GAS) }",
"{ (asm JUMPDEST) }",
"{ (asm PUSH1) }",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, these actually seem to show another bug. They do insert the correct opcode, but there is no possible way to push an immediate, because having a number there will include the PUSH opcode too:

  • (asm PUSH1) -> 0x60
  • (asm PUSH1 0x42) -> 0x60 0x60 0x42
  • (asm 0x42) -> 0x60 0x42

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll push a patch which removes that from assembly, but these tests should be changed to not include PUSHnn, but rather have a literal each for all widths (0x42, 0x4242, ..)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in #3070.

};

for (size_t i = 0; i < opcodes_bytecode.size(); i++) {
std::vector<std::string> errors;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for the std prefix as the namespace is imported, vector<string> should be enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.


if (!errors.empty()) {
BOOST_FAIL(opcodes_lll[i]);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could be replaced with BOOST_REQUIRE_MESSAGE(errors.empty(), opcodes_lll[i]); though I'm not 100% sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done. and yeah, it works.

@jwasinger
Copy link
Contributor Author

I also added opcodes for environmental ops like (BLOCKHASH, TIMESTAMP, etc.)

@axic
Copy link
Contributor

axic commented Oct 18, 2017

Rebased, indented, sorted instructions by opcode number and changed all parameters to be 0 to aid comparing the opcode itself.

@axic axic merged commit 7454a76 into argotorg:develop Oct 18, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants