Merge pull request #2010 from nspcc-dev/check-native-manifest

core: check stored native states against autogenerated ones on start
This commit is contained in:
Roman Khimov 2021-06-10 22:29:52 +03:00 committed by GitHub
commit 0f23f68dab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -348,6 +348,43 @@ func (bc *Blockchain) init() error {
return fmt.Errorf("can't init cache for Management native contract: %w", err) return fmt.Errorf("can't init cache for Management native contract: %w", err)
} }
// Check autogenerated native contracts' manifests and NEFs against the stored ones.
// Need to be done after native Management cache initialisation to be able to get
// contract state from DAO via high-level bc API.
for _, c := range bc.contracts.Contracts {
md := c.Metadata()
history := md.UpdateHistory
if len(history) == 0 || history[0] > bHeight {
continue
}
storedCS := bc.GetContractState(md.Hash)
if storedCS == nil {
return fmt.Errorf("native contract %s is not stored", md.Name)
}
w := io.NewBufBinWriter()
storedCS.EncodeBinary(w.BinWriter)
if w.Err != nil {
return fmt.Errorf("failed to check native %s state against autogenerated one: %w", md.Name, w.Err)
}
buff := w.Bytes()
storedCSBytes := make([]byte, len(buff))
copy(storedCSBytes, buff)
w.Reset()
autogenCS := &state.Contract{
ContractBase: md.ContractBase,
UpdateCounter: storedCS.UpdateCounter, // it can be restored only from the DB, so use the stored value.
}
autogenCS.EncodeBinary(w.BinWriter)
if w.Err != nil {
return fmt.Errorf("failed to check native %s state against autogenerated one: %w", md.Name, w.Err)
}
autogenCSBytes := w.Bytes()
if !bytes.Equal(storedCSBytes, autogenCSBytes) {
return fmt.Errorf("native %s: version mismatch (stored contract state differs from autogenerated one), "+
"try to resynchronize the node from the genesis", md.Name)
}
}
return bc.updateExtensibleWhitelist(bHeight) return bc.updateExtensibleWhitelist(bHeight)
} }