core, rpc: fix height-related issue of historic call functionality

Specifying a certain stateroot R as `invoke*historic` RPC-call
parameter, we're willing to perform historic call based on the storage
state of root R. Thus, next block should be of the height h(R)+1. This
allows to use historic functionality for the current blockchain height.
This commit is contained in:
Anna Shaleva 2022-06-20 18:25:45 +03:00
parent 5108d1c2c7
commit 7c48edaccb
3 changed files with 13 additions and 7 deletions

View file

@ -174,10 +174,12 @@ These methods provide the ability of *historical* calls and accept block hash or
block index or stateroot hash as the first parameter and the list of parameters block index or stateroot hash as the first parameter and the list of parameters
that is the same as of `invokecontractverify`, `invokefunction` and that is the same as of `invokecontractverify`, `invokefunction` and
`invokescript` correspondingly. The historical call assumes that the contracts' `invokescript` correspondingly. The historical call assumes that the contracts'
storage state has all its values got from MPT with the specified stateroot and storage state has all its values got from MPT with the specified stateroot (or,
the transaction will be invoked using interop context with block of the specified which is the same, with the stateroot of the block of the specified height) and
height. This allows to perform test invocation using the specified past chain the transaction will be invoked using interop context with block which is next to
state. These methods may be useful for debugging purposes. the block with the specified height. This allows to perform test invocation using
the specified past chain state. These methods may be useful for debugging
purposes.
Behavior note: any historical RPC call need the historical chain state to be Behavior note: any historical RPC call need the historical chain state to be
presented in the node storage, thus if the node keeps only latest MPT state presented in the node storage, thus if the node keeps only latest MPT state

View file

@ -2187,7 +2187,11 @@ func (bc *Blockchain) GetTestHistoricVM(t trigger.Type, tx *transaction.Transact
} }
mode |= mpt.ModeGCFlag mode |= mpt.ModeGCFlag
} }
sr, err := bc.stateRoot.GetStateRoot(b.Index) if b.Index < 1 || b.Index > bc.BlockHeight()+1 {
return nil, fmt.Errorf("unsupported historic chain's height: requested state for %d, chain height %d", b.Index, bc.blockHeight)
}
// Assuming that block N-th is processing during historic call, the historic invocation should be based on the storage state of height N-1.
sr, err := bc.stateRoot.GetStateRoot(b.Index - 1)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to retrieve stateroot for height %d: %w", b.Index, err) return nil, fmt.Errorf("failed to retrieve stateroot for height %d: %w", b.Index, err)
} }

View file

@ -1780,9 +1780,9 @@ func (s *Server) getHistoricParams(reqParams request.Params) (*block.Block, *res
height = int(b.Index) height = int(b.Index)
} }
} }
b, err := s.getFakeNextBlock(uint32(height)) b, err := s.getFakeNextBlock(uint32(height + 1))
if err != nil { if err != nil {
return nil, response.NewInternalServerError(fmt.Sprintf("can't create fake block for height %d: %s", height, err)) return nil, response.NewInternalServerError(fmt.Sprintf("can't create fake block for height %d: %s", height+1, err))
} }
return b, nil return b, nil
} }