|
|
@ -140,47 +140,96 @@ public class KeyValueStoragePrefixedKeyBlockchainStorage implements BlockchainSt |
|
|
|
return blockchainStorage.get(Bytes.concatenate(prefix, key).toArrayUnsafe()).map(Bytes::wrap); |
|
|
|
return blockchainStorage.get(Bytes.concatenate(prefix, key).toArrayUnsafe()).map(Bytes::wrap); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void migrateVariables() { |
|
|
|
/** |
|
|
|
|
|
|
|
* One time migration of variables from the blockchain storage to the dedicated variable storage. |
|
|
|
|
|
|
|
* To avoid state inconsistency in case of a downgrade done without running the storage |
|
|
|
|
|
|
|
* revert-variables subcommand it fails giving the possibility to retry the downgrade procedure. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private void migrateVariables() { |
|
|
|
final var blockchainUpdater = updater(); |
|
|
|
final var blockchainUpdater = updater(); |
|
|
|
final var variablesUpdater = variablesStorage.updater(); |
|
|
|
final var variablesUpdater = variablesStorage.updater(); |
|
|
|
|
|
|
|
|
|
|
|
get(VARIABLES_PREFIX, CHAIN_HEAD_HASH.getBytes()) |
|
|
|
get(VARIABLES_PREFIX, CHAIN_HEAD_HASH.getBytes()) |
|
|
|
.map(this::bytesToHash) |
|
|
|
.map(this::bytesToHash) |
|
|
|
.ifPresent( |
|
|
|
.ifPresent( |
|
|
|
ch -> { |
|
|
|
bch -> |
|
|
|
variablesUpdater.setChainHead(ch); |
|
|
|
variablesStorage |
|
|
|
LOG.info("Migrated key {} to variables storage", CHAIN_HEAD_HASH); |
|
|
|
.getChainHead() |
|
|
|
}); |
|
|
|
.ifPresentOrElse( |
|
|
|
|
|
|
|
vch -> { |
|
|
|
|
|
|
|
if (!vch.equals(bch)) { |
|
|
|
|
|
|
|
logInconsistencyAndFail(CHAIN_HEAD_HASH, bch, vch); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
() -> { |
|
|
|
|
|
|
|
variablesUpdater.setChainHead(bch); |
|
|
|
|
|
|
|
LOG.info("Migrated key {} to variables storage", CHAIN_HEAD_HASH); |
|
|
|
|
|
|
|
})); |
|
|
|
|
|
|
|
|
|
|
|
get(VARIABLES_PREFIX, FINALIZED_BLOCK_HASH.getBytes()) |
|
|
|
get(VARIABLES_PREFIX, FINALIZED_BLOCK_HASH.getBytes()) |
|
|
|
.map(this::bytesToHash) |
|
|
|
.map(this::bytesToHash) |
|
|
|
.ifPresent( |
|
|
|
.ifPresent( |
|
|
|
fh -> { |
|
|
|
bfh -> { |
|
|
|
variablesUpdater.setFinalized(fh); |
|
|
|
variablesStorage |
|
|
|
LOG.info("Migrated key {} to variables storage", FINALIZED_BLOCK_HASH); |
|
|
|
.getFinalized() |
|
|
|
|
|
|
|
.ifPresentOrElse( |
|
|
|
|
|
|
|
vfh -> { |
|
|
|
|
|
|
|
if (!vfh.equals(bfh)) { |
|
|
|
|
|
|
|
logInconsistencyAndFail(FINALIZED_BLOCK_HASH, bfh, vfh); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
() -> { |
|
|
|
|
|
|
|
variablesUpdater.setFinalized(bfh); |
|
|
|
|
|
|
|
LOG.info("Migrated key {} to variables storage", FINALIZED_BLOCK_HASH); |
|
|
|
|
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
get(VARIABLES_PREFIX, SAFE_BLOCK_HASH.getBytes()) |
|
|
|
get(VARIABLES_PREFIX, SAFE_BLOCK_HASH.getBytes()) |
|
|
|
.map(this::bytesToHash) |
|
|
|
.map(this::bytesToHash) |
|
|
|
.ifPresent( |
|
|
|
.ifPresent( |
|
|
|
sh -> { |
|
|
|
bsh -> { |
|
|
|
variablesUpdater.setSafeBlock(sh); |
|
|
|
variablesStorage |
|
|
|
LOG.info("Migrated key {} to variables storage", SAFE_BLOCK_HASH); |
|
|
|
.getSafeBlock() |
|
|
|
|
|
|
|
.ifPresentOrElse( |
|
|
|
|
|
|
|
vsh -> { |
|
|
|
|
|
|
|
if (!vsh.equals(bsh)) { |
|
|
|
|
|
|
|
logInconsistencyAndFail(SAFE_BLOCK_HASH, bsh, vsh); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
() -> { |
|
|
|
|
|
|
|
variablesUpdater.setSafeBlock(bsh); |
|
|
|
|
|
|
|
LOG.info("Migrated key {} to variables storage", SAFE_BLOCK_HASH); |
|
|
|
|
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
get(VARIABLES_PREFIX, FORK_HEADS.getBytes()) |
|
|
|
get(VARIABLES_PREFIX, FORK_HEADS.getBytes()) |
|
|
|
.map(bytes -> RLP.input(bytes).readList(in -> this.bytesToHash(in.readBytes32()))) |
|
|
|
.map(bytes -> RLP.input(bytes).readList(in -> this.bytesToHash(in.readBytes32()))) |
|
|
|
.ifPresent( |
|
|
|
.ifPresent( |
|
|
|
fh -> { |
|
|
|
bfh -> { |
|
|
|
variablesUpdater.setForkHeads(fh); |
|
|
|
final var vfh = variablesStorage.getForkHeads(); |
|
|
|
LOG.info("Migrated key {} to variables storage", FORK_HEADS); |
|
|
|
if (vfh.isEmpty()) { |
|
|
|
|
|
|
|
variablesUpdater.setForkHeads(bfh); |
|
|
|
|
|
|
|
LOG.info("Migrated key {} to variables storage", FORK_HEADS); |
|
|
|
|
|
|
|
} else if (!List.copyOf(vfh).equals(bfh)) { |
|
|
|
|
|
|
|
logInconsistencyAndFail(FORK_HEADS, bfh, vfh); |
|
|
|
|
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
get(Bytes.EMPTY, SEQ_NO_STORE.getBytes()) |
|
|
|
get(Bytes.EMPTY, SEQ_NO_STORE.getBytes()) |
|
|
|
.ifPresent( |
|
|
|
.ifPresent( |
|
|
|
sns -> { |
|
|
|
bsns -> { |
|
|
|
variablesUpdater.setLocalEnrSeqno(sns); |
|
|
|
variablesStorage |
|
|
|
LOG.info("Migrated key {} to variables storage", SEQ_NO_STORE); |
|
|
|
.getLocalEnrSeqno() |
|
|
|
|
|
|
|
.ifPresentOrElse( |
|
|
|
|
|
|
|
vsns -> { |
|
|
|
|
|
|
|
if (!vsns.equals(bsns)) { |
|
|
|
|
|
|
|
logInconsistencyAndFail(SEQ_NO_STORE, bsns, vsns); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
() -> { |
|
|
|
|
|
|
|
variablesUpdater.setLocalEnrSeqno(bsns); |
|
|
|
|
|
|
|
LOG.info("Migrated key {} to variables storage", SEQ_NO_STORE); |
|
|
|
|
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
blockchainUpdater.removeVariables(); |
|
|
|
blockchainUpdater.removeVariables(); |
|
|
@ -189,6 +238,17 @@ public class KeyValueStoragePrefixedKeyBlockchainStorage implements BlockchainSt |
|
|
|
blockchainUpdater.commit(); |
|
|
|
blockchainUpdater.commit(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static void logInconsistencyAndFail( |
|
|
|
|
|
|
|
final VariablesStorage.Keys key, final Object bch, final Object vch) { |
|
|
|
|
|
|
|
LOG.error( |
|
|
|
|
|
|
|
"Inconsistency found when migrating {} to variables storage," |
|
|
|
|
|
|
|
+ " probably this is due to a downgrade done without running the `storage revert-variables`" |
|
|
|
|
|
|
|
+ " subcommand first, see https://github.com/hyperledger/besu/pull/5471", |
|
|
|
|
|
|
|
key); |
|
|
|
|
|
|
|
throw new IllegalStateException( |
|
|
|
|
|
|
|
key + " mismatch: blockchain storage value=" + bch + ", variables storage value=" + vch); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public static class Updater implements BlockchainStorage.Updater { |
|
|
|
public static class Updater implements BlockchainStorage.Updater { |
|
|
|
|
|
|
|
|
|
|
|
private final KeyValueStorageTransaction blockchainTransaction; |
|
|
|
private final KeyValueStorageTransaction blockchainTransaction; |
|
|
|