Comments (2)
Current State of Affairs
We currently manipulate and represent addresses as:
newtype Address = Address ByteString
where the address internal representation is the whole address payload on Byron. In other
words, the ByteString
is a cbor encoding of various consistuent derived from the address
public key.
We represent addresses in a human-friendly way using a Base58
encoding at the API-level.
This goes though ToText
and FromText
instances:
instance FromText Address where
fromText x = maybe
(Left $ TextDecodingError err)
(pure . Address)
(decodeBase58 bitcoinAlphabet $ T.encodeUtf8 x)
where
err = "Unable to decode Address: expected Base58 encoding"
instance ToText Address where
toText = T.decodeUtf8 . encodeBase58 bitcoinAlphabet . getAddress
We do also currently use this address instance to serialize to and deserialize form the
database.
NOTE
:There's a problem inherent to our current design: using an invalid address (which has
however a valid base58 encoding, throws hard because we only verify the address payload
when encoding it). This can be fixed by forcing the payload to be decoded when parsing the address
from a base58 text string.
Problem to solve
In Shelley, addresses can be one of these three formats:
- Byron addresses, as described above
- Single addresses, holding only a public spending key
- Group addresses, holding both a spending key and delegation key
In addition to these format, we also have a new user-facing encoding for Single
and
Group
addresses: bech32
.
New Address Data-Type
One area to explore would be to change Address
definition with:
data Address
= ByronAddress !ByteString
| SingleAddress !???
| GroupAddress !??? !???
This allows for clearly capturing within the Address
type itself, what the encoding should be.
Now, what to put in ???
, this requires some thoughts:
-
XPub
seems like the most legitimate choice (since the address is a concatenation of a
discriminant byte and a public key). However, how do we parse an address then? We would
need to verify the discriminant byte and therefore, know what is the underlyingnetwork
.
This is something we don't know within thecore
package because this depends on the
target backend we select. So the transformation from and to bech32 text has to be done within
the corresponding backend package. -
ByteString
is a sensible choice here too despite the lost of expressiveness at the type-level (which isn't necessarily a bad thing, cf below). Storing the whole address payload as a
rawByteString
helps to keep the whole core engine fairly agnostic to what the internals of an address are, leaving them up to the node backend.
Drawbacks
Although elegant from the design perspective, this approach present one major drawback:
We then have to consider addresses always as a sum type between these three constructors whereas, in most places (except at the edge of the application), addresses are really just treated as an opaque type; a wrapper around a payload so-to-speak.
The content of that payload is interesting only when we want to display the address in a human-friendly way. For the rest, we do maintain a dictionary of Address -> Derivation Index in the BIP-44 pools so address can be derived from their account key if necessary (and we do need this anyway to recover the private key from an address!).
Considering a sum-type means that we would have to consider testing all branches, and their possible interaction with the rest of the codebase, whereas they're all treated in an exact same way. Also, what happened for the code within the bridge, jormungandr or shelley haskell for they use different branches of this sum-type (bridge doesn't have group and single address, shelley haskell has extra "pointer" branches that aren't yet in jormungandr etc ...).
Keep it simple
On the contrary, keeping the address definition as simply a wrapper around a raw bytestring presents many advantages. For most of the code, the 'Address' remains quite opaque and is treated as such. We only consider the encoding at the edge of the application, for what is user-facing (i.e. the API) and we defer that decision to the backend package via proper type classes parameterized by the backend parameter.
This also gives us a very easy testing (as we do now) where the payload of an address can pretty much be anything. When it matters (comparing or submitting transactions), then we may shove in a relevant payload that is compatible with the target backend.
Parameterizing over the backend type
As we do for TxId
, it is possible to parameterize our wallet layer over a target
(or t
)
type parameter which embeds the address format. This allows for keeping the address encoding
outside of the wallet core logic, decided by the caller / target backend. In particular,
it makes it possible to use different encoding on different backend, and/or, disallow specific
encodings or address constructors.
class EncodeAddress t where
encodeAddress :: Proxy t -> Address -> Text
class DecodeAddress t where
decodeAddress :: Proxy t -> Text -> Either TextDecodingError Address
So here, depending on which backend we're dealing with, we may end up rejecting addresses that are encoded in bech32, or those with a wrong network magic. The encoding is also a bit subtle as the instances will have to peek into the address raw bytes to determine what sort of address it is. Still, this is a fair price to pay for simplicity.
from cardano-wallet.
lgtm! 👍
from cardano-wallet.
Related Issues (20)
- Store keys in Hashicorp Vault HOT 2
- Stake pool monitor exit: Unhandled exception: SQLite3 returned ErrorIO while attempting to perform step: disk I/O error HOT 5
- Upgrade cardano-wallet to build with ghc-9.6 HOT 1
- Compatibility with `cardano-node` version `8.0.0` HOT 10
- Adahandle support
- Publish tag 2023-07-18 on Docker hub HOT 2
- Invalid link in `CONTRIBUTING.md` file HOT 2
- Cardano wallet's threads are dying while syncing HOT 1
- MacOS ARM64 builds HOT 3
- Can't sign tx with "mustBeSignedBy" constraint with a stakeKey. HOT 3
- Expose Wallet Engine Sync Progress API HOT 4
- cardano-wallet is not getting synced up HOT 12
- cabal build all with v2023-07-18 tag not working HOT 1
- Documentation / interface for hardware wallets HOT 3
- CHaP release HOT 3
- "The machine terminated part way through evaluation due to overspending the budget" HOT 1
- Quickstart Bash Script Error: tar file cannot be decoded. HOT 1
- cardano-wallet NixOS module not working with cardano-node NixOS module HOT 1
- 🐞 Bug: JSON roundtrip property broken for `TxMetadataWithSchema`. HOT 2
- 🐞 Bug: HTTP API returns "Internal Server Error" when attempting to encrypt multiple transaction metadata messages. HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from cardano-wallet.