From 5709315d60aeaad7b406c5176d22d158b2c0ee11 Mon Sep 17 00:00:00 2001 From: laizy Date: Fri, 11 Oct 2019 11:22:14 +0800 Subject: [PATCH] allow vm reader eof error to avoid hard-fork in testnet (#1092) --- core/store/ledgerstore/ledger_store.go | 3 ++- smartcontract/smart_contract.go | 1 + vm/neovm/execution_context.go | 24 ++++++++++++++---------- vm/neovm/executor.go | 5 +++-- vm/neovm/utils/vm_reader.go | 9 ++++++++- 5 files changed, 28 insertions(+), 14 deletions(-) diff --git a/core/store/ledgerstore/ledger_store.go b/core/store/ledgerstore/ledger_store.go index cda8c3ae61..4ff8b7fe8f 100644 --- a/core/store/ledgerstore/ledger_store.go +++ b/core/store/ledgerstore/ledger_store.go @@ -850,7 +850,8 @@ func (this *LedgerStoreImp) saveBlock(block *types.Block, stateMerkleRoot common } if result.MerkleRoot != stateMerkleRoot { - return errors.NewErr("state merkle root mismatch!") + return fmt.Errorf("state merkle root mismatch. expected: %s, got: %s", + result.MerkleRoot.ToHexString(), stateMerkleRoot.ToHexString()) } return this.submitBlock(block, result) diff --git a/smartcontract/smart_contract.go b/smartcontract/smart_contract.go index d592b96f76..555c0d2dd3 100644 --- a/smartcontract/smart_contract.go +++ b/smartcontract/smart_contract.go @@ -128,6 +128,7 @@ func NewVmFeatureFlag(blockHeight uint32) vm.VmFeatureFlag { var feature vm.VmFeatureFlag enableHeight := config.GetOpcodeUpdateCheckHeight(config.DefConfig.P2PNode.NetworkId) feature.DisableHasKey = blockHeight <= enableHeight + feature.AllowReaderEOF = blockHeight <= enableHeight return feature } diff --git a/vm/neovm/execution_context.go b/vm/neovm/execution_context.go index 05d8b1876c..4cc8ae79b5 100644 --- a/vm/neovm/execution_context.go +++ b/vm/neovm/execution_context.go @@ -28,14 +28,18 @@ type ExecutionContext struct { Code []byte OpReader *utils.VmReader InstructionPointer int + vmFlags VmFeatureFlag } -func NewExecutionContext(code []byte) *ExecutionContext { - var executionContext ExecutionContext - executionContext.Code = code - executionContext.OpReader = utils.NewVmReader(code) - executionContext.InstructionPointer = 0 - return &executionContext +func NewExecutionContext(code []byte, flag VmFeatureFlag) *ExecutionContext { + var context ExecutionContext + context.Code = code + context.OpReader = utils.NewVmReader(code) + context.OpReader.AllowEOF = flag.AllowReaderEOF + context.vmFlags = flag + + context.InstructionPointer = 0 + return &context } func (ec *ExecutionContext) GetInstructionPointer() int { @@ -62,8 +66,8 @@ func (self *ExecutionContext) ReadOpCode() (val OpCode, eof bool) { } func (ec *ExecutionContext) Clone() *ExecutionContext { - executionContext := NewExecutionContext(ec.Code) - executionContext.InstructionPointer = ec.InstructionPointer - _ = executionContext.SetInstructionPointer(int64(ec.GetInstructionPointer())) - return executionContext + context := NewExecutionContext(ec.Code, ec.vmFlags) + context.InstructionPointer = ec.InstructionPointer + _ = context.SetInstructionPointer(int64(ec.GetInstructionPointer())) + return context } diff --git a/vm/neovm/executor.go b/vm/neovm/executor.go index 4c22677f09..91ac078bae 100644 --- a/vm/neovm/executor.go +++ b/vm/neovm/executor.go @@ -33,14 +33,15 @@ import ( ) type VmFeatureFlag struct { - DisableHasKey bool // disable haskey, dcall, values opcode + DisableHasKey bool // disable haskey, dcall, values opcode + AllowReaderEOF bool // allow VmReader.ReadBytes got EOF and return 0 bytes } func NewExecutor(code []byte, feature VmFeatureFlag) *Executor { var engine Executor engine.EvalStack = NewValueStack(STACK_LIMIT) engine.AltStack = NewValueStack(STACK_LIMIT) - context := NewExecutionContext(code) + context := NewExecutionContext(code, feature) engine.Context = context engine.State = BREAK engine.Features = feature diff --git a/vm/neovm/utils/vm_reader.go b/vm/neovm/utils/vm_reader.go index 5e4fc9e516..ad2385cdb9 100644 --- a/vm/neovm/utils/vm_reader.go +++ b/vm/neovm/utils/vm_reader.go @@ -27,6 +27,7 @@ import ( type VmReader struct { reader *bytes.Reader BaseStream []byte + AllowEOF bool // allow VmReader.ReadBytes got EOF and return 0 bytes } func NewVmReader(b []byte) *VmReader { @@ -43,10 +44,16 @@ func (r *VmReader) ReadByte() (byte, error) { func (r *VmReader) ReadBytes(count int) ([]byte, error) { // first check to avoid memory attack - if r.reader.Len() < count { + amount := r.reader.Len() + if r.AllowEOF { + amount = 1 * 1024 * 1024 + } + if amount < count { return nil, io.EOF } b := make([]byte, count) + // when reader does not has enough bytes, it will return the actual length and error is nil + // this is a bug previously(it should use io.ReadFull), but we have to keep it to avoid hard fork _, err := r.reader.Read(b) if err != nil { return nil, err