-
Notifications
You must be signed in to change notification settings - Fork 712
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
Test Address versionning #3417
Test Address versionning #3417
Conversation
Address::AddressV1 and Address::AddressV2 variants, each made with a different Hash algorithm. /!\ The code compiles, but there should be some errors in the way we handle both versions!
Some example of refactoring we would have to do: In
The Address size is basically hardcoded in the way we store the ledger. |
Address versioning
First thoughts:To simplify, we only worry about the transition between two address versions, AddressV0 and AddressV1. Vocabulary:
Thread handlingScenarioAlice has 5 coins in her wallet, and maintains two nodes (one using AddressV0 and one using AddressV1).
Here, maybe the double spend would be caught eventually (through cross-thread syncs), but it would lead to a lot of inefficiencies (because it takes too much time to realize some blocks are incompatible and this hinders finality). Methods to protect against this problem
Smart contract handlingScenarioAt T0, Alice publishes a smart contract After T2, the smart contract
Bob would need to access the smart contract from his AddressV0, or "update" it to link the two addresses together. After T2, the smart contract
Argument handling of address types in smart contractsIn legacy contracts
In new contracts
Smart contract addresses access
The address of a smart contract is computed in pub fn create_new_sc_address(&mut self, bytecode: Vec<u8>) -> Result<Address, ExecutionError> In particular, it is computed has a hash of deterministic data let mut data: Vec<u8> = self.slot.to_bytes_key().to_vec();
// add the index of the created address within this context to the seed
data.append(&mut self.created_addr_index.to_be_bytes().to_vec());
// add a flag on whether we are in read-only mode or not to the seed
// this prevents read-only contexts from shadowing existing addresses
if self.read_only {
data.push(0u8);
} else {
data.push(1u8);
}
let address = Address::AddressV2(AddressV2(massa_hash::HashV2::compute_from(&data))); Changing the hash algorithm will produce new contract addresses easily. Implementation choices
References
|
How about forcing simultaneous versioning of addresses + keys ? eg. even if only the hashing algo is updated, the version numbers of newly created keys is also updated. And when the signature algo is updated, also increment the version of the derived addresses. In that case, the Address structure can be an enum (like https://doc.rust-lang.org/std/net/enum.IpAddr.html ) with the following methods, each managing address types with a
The PublicKey structure can also be an enum, and expose a compute_address(&self) -> Address method that yields the right address version. Advantage: the "version" is actually the "crypto version" in use (where "crypto" is the (hash, sig) pair of algorithms) Disvantage: both addresses and keys get an extra enum element even if just one of them changed, and updating address version always means creating a new account. Still feels like the least error-prone approach |
This seems like a neet idea! @AurelienFT is currently working on a set of macros helping the versioning our various structures (avoiding some code duplication). I think that versioning the Address and the KeyPair together is a good way to avoid some problems (and to lean into the "the updated address is distinct from the previous one" idea that avoids hacks such as translation maps). |
Address::AddressV1 and Address::AddressV2 variants, each made with a different Hash algorithm.
/!\ The code compiles, but there should be some errors in the way we handle both versions!