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
Introduce version and fix various bugs #99
Introduce version and fix various bugs #99
Conversation
pub const OP_SUB: InstructionOpcode = 62; | ||
pub const OP_SUBW: InstructionOpcode = 63; | ||
pub const OP_SW: InstructionOpcode = 64; | ||
pub const OP_VERSION1_JALR: InstructionOpcode = 65; |
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.
Any reason to allocate different instructon opcode? From the code base, it seems that OP_VERSION1_JALR
and OP_JALR
lead to identical logic.
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.
The 2 opcodes actually do use different logic:
ckb-vm/src/machine/asm/execute.S
Lines 448 to 456 in 01cf746
.CKB_VM_ASM_LABEL_OP_JALR: | |
DECODE_I | |
movq PC_ADDRESS, TEMP1 | |
WRITE_RD(TEMP1) | |
movq REGISTER_ADDRESS(RS1), TEMP1 | |
addq IMMEDIATE, TEMP1 | |
andq $-2, TEMP1 | |
movq TEMP1, PC_ADDRESS | |
jmp .prepare_trace |
ckb-vm/src/machine/asm/execute.S
Lines 1093 to 1101 in 01cf746
.CKB_VM_ASM_LABEL_OP_VERSION1_JALR: | |
DECODE_I | |
movq REGISTER_ADDRESS(RS1), RS2r | |
movq PC_ADDRESS, TEMP1 | |
WRITE_RD(TEMP1) | |
addq IMMEDIATE, RS2r | |
andq $-2, RS2r | |
movq RS2r, PC_ADDRESS | |
jmp .prepare_trace |
Notice the first 4 lines in each version, they are in different orders. The idea is that version 0 can use the original OP_JALR
, while version 1 and later uses OP_VERSION1_JALR
01cf746
to
c4bc509
Compare
if version0 { | ||
let address = address.to_u64(); | ||
let end = address.checked_add(bytes).ok_or(Error::OutOfBound)?; | ||
if end == RISCV_MAX_MEMORY as u64 { |
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 am curious why it is not end >= RISCV_MAX_MEMORY
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.
The >
case will be covered by normal memory module bound checking code. This bug only occurs with the ==
case.
If we use |
I think we do, based on my understanding of forks, assuming we do a fork update at block 3000000, we will need to use VERSION0 to validate blocks under 3000000 to preserve compatibility, and use VERSION1 to validate blocks after 3000000. That means we will need the concept of version even if we split a release branch. |
Since one major use case of CKB VM is on blockchains, we cannot just change the code in case of bugs. We have to wait for the next fork event, only then can we upgrade the code. Hence we are introducing a concept of versions in the VM, whenever we fix a bug that might alter behavior, we will insert checking code to only include the bug fix in the next VM version. This way blockchains can expect consistent VM behavior when they lock specific VM version.
255729d
to
59b076d
Compare
It’s likely that we’ll run v0 for codes stored in cells created before a height, and v1 afterwards. Genesis system scripts are exceptions. |
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.
LGTM
This makes sense but I don't think we need to make exceptions for genesis scripts. They can be treated as scripts created before the fork, hence v0 will be used. Later if there is the need to upgrade them, they might be created into new cells, which can leverage v1 or newer versions. |
Since one major use case of CKB VM is on blockchains, we cannot just
change the code in case of bugs. We have to wait for the next fork
event, only then can we upgrade the code. Hence we are introducing a
concept of versions in the VM, whenever we fix a bug that might alter
behavior, we will insert checking code to only include the bug fix in
the next VM version. This way blockchains can expect consistent VM
behavior when they lock specific VM version.
This PR also provides VM version 1 which fixes #92 #97 and #98