Skip to content

Commit c8b9cd9

Browse files
authored
Merge pull request #327 from input-output-hk/whankinsiv/historical-accounts-address-indexing
feat: historical accounts Shelley address indexing
2 parents 5dadbfc + 39a8919 commit c8b9cd9

File tree

14 files changed

+619
-165
lines changed

14 files changed

+619
-165
lines changed

common/src/address.rs

Lines changed: 178 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#![allow(dead_code)]
44

55
use crate::cip19::{VarIntDecoder, VarIntEncoder};
6+
use crate::hash::Hash;
67
use crate::{Credential, KeyHash, NetworkId, ScriptHash, StakeCredential};
78
use anyhow::{anyhow, bail, Result};
89
use crc::{Crc, CRC_32_ISO_HDLC};
@@ -294,7 +295,7 @@ impl ShelleyAddress {
294295
Ok(bech32::encode::<bech32::Bech32>(hrp, &data)?)
295296
}
296297

297-
pub fn to_bytes_key(&self) -> Result<Vec<u8>> {
298+
pub fn to_bytes_key(&self) -> Vec<u8> {
298299
let network_bits = match self.network {
299300
NetworkId::Mainnet => 1u8,
300301
NetworkId::Testnet => 0u8,
@@ -307,8 +308,10 @@ impl ShelleyAddress {
307308

308309
let mut data = Vec::new();
309310

310-
let build_header =
311-
|variant: u8| -> u8 { network_bits | (payment_bits << 4) | (variant << 5) };
311+
let build_header = |delegation_bits: u8| -> u8 {
312+
let addr_type = ((delegation_bits & 0x03) << 1) | (payment_bits & 0x01);
313+
(addr_type << 4) | (network_bits & 0x0F)
314+
};
312315

313316
match &self.delegation {
314317
ShelleyAddressDelegationPart::None => {
@@ -341,7 +344,76 @@ impl ShelleyAddress {
341344
}
342345
}
343346

344-
Ok(data)
347+
data
348+
}
349+
350+
pub fn from_bytes_key(data: &[u8]) -> Result<Self> {
351+
if data.is_empty() {
352+
return Err(anyhow!("empty address bytes"));
353+
}
354+
355+
let header = data[0];
356+
357+
if header & 0x80 != 0 {
358+
return Err(anyhow!("invalid header: high bit set"));
359+
}
360+
361+
let network = match header & 0x0F {
362+
0 => NetworkId::Testnet,
363+
1 => NetworkId::Mainnet,
364+
_ => return Err(anyhow!("invalid network bits in header")),
365+
};
366+
367+
let addr_type = (header >> 4) & 0x0F;
368+
369+
let payment_bits = addr_type & 0x01;
370+
let delegation_bits = (addr_type >> 1) & 0x03;
371+
372+
let payment_hash = {
373+
let mut arr = [0u8; 28];
374+
arr.copy_from_slice(&data[1..29]);
375+
Hash::<28>::new(arr)
376+
};
377+
378+
let payment = match payment_bits {
379+
0 => ShelleyAddressPaymentPart::PaymentKeyHash(payment_hash),
380+
1 => ShelleyAddressPaymentPart::ScriptHash(payment_hash),
381+
_ => return Err(anyhow!("invalid payment bits")),
382+
};
383+
384+
let delegation = match delegation_bits {
385+
0 => {
386+
let mut arr = [0u8; 28];
387+
arr.copy_from_slice(&data[29..57]);
388+
ShelleyAddressDelegationPart::StakeKeyHash(Hash::<28>::new(arr))
389+
}
390+
1 => {
391+
let mut arr = [0u8; 28];
392+
arr.copy_from_slice(&data[29..57]);
393+
ShelleyAddressDelegationPart::ScriptHash(Hash::<28>::new(arr))
394+
}
395+
2 => {
396+
let mut decoder = VarIntDecoder::new(&data[29..]);
397+
let slot = decoder.read()?;
398+
let tx_index = decoder.read()?;
399+
let cert_index = decoder.read()?;
400+
401+
ShelleyAddressDelegationPart::Pointer(ShelleyAddressPointer {
402+
slot,
403+
tx_index,
404+
cert_index,
405+
})
406+
}
407+
3 => ShelleyAddressDelegationPart::None,
408+
409+
_ => return Err(anyhow!("invalid delegation bits")),
410+
};
411+
412+
Ok(ShelleyAddress {
413+
network,
414+
payment,
415+
delegation,
416+
})
345417
}
346418

347419
pub fn stake_address_string(&self) -> Result<Option<String>> {
@@ -600,7 +672,7 @@ impl Address {
600672
match self {
601673
Address::Byron(b) => b.to_bytes_key(),
602674

603-
Address::Shelley(s) => s.to_bytes_key(),
675+
Address::Shelley(s) => Ok(s.to_bytes_key()),
604676

605677
Address::Stake(stake) => stake.to_bytes_key(),
606678

@@ -652,7 +724,7 @@ impl PartialOrd for BechOrdAddress {
652724
#[cfg(test)]
653725
mod tests {
654726
use super::*;
655-
use crate::crypto::keyhash_224;
727+
use crate::{crypto::keyhash_224, hash::Hash};
656728
use minicbor::{Decode, Encode};
657729

658730
#[test]
@@ -1047,4 +1119,104 @@ mod tests {
10471119
let result = StakeAddress::decode(&mut decoder, &mut ());
10481120
assert!(result.is_err());
10491121
}
1122+
1123+
#[test]
1124+
fn test_shelley_address_to_from_bytes_key_roundtrip() {
1125+
let payment_hash = Hash::new([0x11; 28]);
1126+
let stake_hash = Hash::new([0x22; 28]);
1127+
let script_hash = Hash::new([0x33; 28]);
1128+
1129+
// (KeyHash, StakeKeyHash)
1130+
let type_1 = ShelleyAddress {
1131+
network: NetworkId::Mainnet,
1132+
payment: ShelleyAddressPaymentPart::PaymentKeyHash(payment_hash),
1133+
delegation: ShelleyAddressDelegationPart::StakeKeyHash(stake_hash),
1134+
};
1135+
let bytes = type_1.to_bytes_key();
1136+
assert_eq!(bytes[0], 0x01);
1137+
let decoded = ShelleyAddress::from_bytes_key(&bytes).expect("decode base");
1138+
assert_eq!(type_1, decoded);
1139+
1140+
// (ScriptKeyHash, StakeKeyHash)
1141+
let type_2 = ShelleyAddress {
1142+
network: NetworkId::Mainnet,
1143+
payment: ShelleyAddressPaymentPart::ScriptHash(payment_hash),
1144+
delegation: ShelleyAddressDelegationPart::StakeKeyHash(stake_hash),
1145+
};
1146+
let bytes = type_2.to_bytes_key();
1147+
assert_eq!(bytes[0], 0x11);
1148+
let decoded = ShelleyAddress::from_bytes_key(&bytes).expect("decode base");
1149+
assert_eq!(type_2, decoded);
1150+
1151+
// (KeyHash, ScriptHash)
1152+
let type_3 = ShelleyAddress {
1153+
network: NetworkId::Mainnet,
1154+
payment: ShelleyAddressPaymentPart::PaymentKeyHash(payment_hash),
1155+
delegation: ShelleyAddressDelegationPart::ScriptHash(stake_hash),
1156+
};
1157+
let bytes = type_3.to_bytes_key();
1158+
assert_eq!(bytes[0], 0x21);
1159+
let decoded = ShelleyAddress::from_bytes_key(&bytes).expect("decode base");
1160+
assert_eq!(type_3, decoded);
1161+
1162+
// (ScriptHash, ScriptHash)
1163+
let type_4 = ShelleyAddress {
1164+
network: NetworkId::Mainnet,
1165+
payment: ShelleyAddressPaymentPart::ScriptHash(payment_hash),
1166+
delegation: ShelleyAddressDelegationPart::ScriptHash(script_hash),
1167+
};
1168+
let bytes = type_4.to_bytes_key();
1169+
assert_eq!(bytes[0], 0x31);
1170+
let decoded = ShelleyAddress::from_bytes_key(&bytes).expect("decode script");
1171+
assert_eq!(type_4, decoded);
1172+
1173+
// (KeyHash, Pointer)
1174+
let pointer = ShelleyAddressPointer {
1175+
slot: 1234,
1176+
tx_index: 56,
1177+
cert_index: 2,
1178+
};
1179+
let type_5 = ShelleyAddress {
1180+
network: NetworkId::Mainnet,
1181+
payment: ShelleyAddressPaymentPart::PaymentKeyHash(payment_hash),
1182+
delegation: ShelleyAddressDelegationPart::Pointer(pointer.clone()),
1183+
};
1184+
let bytes = type_5.to_bytes_key();
1185+
assert_eq!(bytes[0], 0x41);
1186+
let decoded = ShelleyAddress::from_bytes_key(&bytes).expect("decode pointer");
1187+
assert_eq!(type_5, decoded);
1188+
1189+
// (ScriptHash, Pointer)
1190+
let type_6 = ShelleyAddress {
1191+
network: NetworkId::Mainnet,
1192+
payment: ShelleyAddressPaymentPart::ScriptHash(payment_hash),
1193+
delegation: ShelleyAddressDelegationPart::Pointer(pointer),
1194+
};
1195+
let bytes = type_6.to_bytes_key();
1196+
assert_eq!(bytes[0], 0x51);
1197+
let decoded = ShelleyAddress::from_bytes_key(&bytes).expect("decode pointer");
1198+
assert_eq!(type_6, decoded);
1199+
1200+
// (KeyHash, None)
1201+
let type_7 = ShelleyAddress {
1202+
network: NetworkId::Mainnet,
1203+
payment: ShelleyAddressPaymentPart::PaymentKeyHash(payment_hash),
1204+
delegation: ShelleyAddressDelegationPart::None,
1205+
};
1206+
let bytes = type_7.to_bytes_key();
1207+
assert_eq!(bytes[0], 0x61);
1208+
let decoded = ShelleyAddress::from_bytes_key(&bytes).expect("decode none");
1209+
assert_eq!(type_7, decoded);
1210+
1211+
// (ScriptHash, None)
1212+
let type_8 = ShelleyAddress {
1213+
network: NetworkId::Mainnet,
1214+
payment: ShelleyAddressPaymentPart::ScriptHash(payment_hash),
1215+
delegation: ShelleyAddressDelegationPart::None,
1216+
};
1217+
let bytes = type_8.to_bytes_key();
1218+
assert_eq!(bytes[0], 0x71);
1219+
let decoded = ShelleyAddress::from_bytes_key(&bytes).expect("decode none");
1220+
assert_eq!(type_8, decoded);
1221+
}
10501222
}

common/src/queries/accounts.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use std::collections::HashMap;
22

3-
use crate::{DRepChoice, PoolId, PoolLiveStakeInfo, RewardType, StakeAddress, TxIdentifier};
3+
use crate::{
4+
DRepChoice, PoolId, PoolLiveStakeInfo, RewardType, ShelleyAddress, StakeAddress, TxIdentifier,
5+
};
46

57
pub const DEFAULT_ACCOUNTS_QUERY_TOPIC: (&str, &str) =
68
("accounts-state-query-topic", "cardano.query.accounts");
@@ -19,7 +21,7 @@ pub enum AccountsStateQuery {
1921
GetAccountDelegationHistory { account: StakeAddress },
2022
GetAccountMIRHistory { account: StakeAddress },
2123
GetAccountWithdrawalHistory { account: StakeAddress },
22-
GetAccountAssociatedAddresses { stake_key: Vec<u8> },
24+
GetAccountAssociatedAddresses { account: StakeAddress },
2325
GetAccountAssets { stake_key: Vec<u8> },
2426
GetAccountAssetsTotals { stake_key: Vec<u8> },
2527
GetAccountUTxOs { stake_key: Vec<u8> },
@@ -53,7 +55,7 @@ pub enum AccountsStateQueryResponse {
5355
AccountDelegationHistory(Vec<DelegationUpdate>),
5456
AccountMIRHistory(Vec<AccountWithdrawal>),
5557
AccountWithdrawalHistory(Vec<AccountWithdrawal>),
56-
AccountAssociatedAddresses(AccountAssociatedAddresses),
58+
AccountAssociatedAddresses(Vec<ShelleyAddress>),
5759
AccountAssets(AccountAssets),
5860
AccountAssetsTotals(AccountAssetsTotals),
5961
AccountUTxOs(AccountUTxOs),

0 commit comments

Comments
 (0)