discovery.rs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. use crate::traits::Roles;
  2. use codec::{Decode, Encode};
  3. use rstd::prelude::*;
  4. #[cfg(feature = "std")]
  5. use serde::{Deserialize, Serialize};
  6. use srml_support::{decl_event, decl_module, decl_storage, ensure};
  7. use system::{self, ensure_root, ensure_signed};
  8. /*
  9. Although there is support for ed25519 keys as the IPNS identity key and we could potentially
  10. reuse the same key for the role account and ipns (and make this discovery module obselete)
  11. it is probably better to separate concerns.
  12. Why not to use a fixed size 32byte -> SHA256 hash of public key: because we would have to force
  13. specific key type on ipfs side.
  14. pub struct IPNSIdentity(pub [u8; 32]); // we loose the key type!
  15. pub type IPNSIdentity(pub u8, pub [u8; 32]); // we could add the keytype?
  16. can we use rust library in wasm runtime?
  17. https://github.com/multiformats/rust-multihash
  18. https://github.com/multiformats/multicodec/
  19. https://github.com/multiformats/multihash/
  20. */
  21. /// base58 encoded IPNS identity multihash codec
  22. pub type IPNSIdentity = Vec<u8>;
  23. /// HTTP Url string to a discovery service endpoint
  24. pub type Url = Vec<u8>;
  25. pub const MINIMUM_LIFETIME: u32 = 600; // 1hr assuming 6s block times
  26. pub const DEFAULT_LIFETIME: u32 = MINIMUM_LIFETIME * 24; // 24hr
  27. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  28. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  29. pub struct AccountInfo<BlockNumber> {
  30. /// IPNS Identity
  31. pub identity: IPNSIdentity,
  32. /// Block at which information expires
  33. pub expires_at: BlockNumber,
  34. }
  35. pub trait Trait: system::Trait {
  36. type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
  37. type Roles: Roles<Self>;
  38. }
  39. decl_storage! {
  40. trait Store for Module<T: Trait> as Discovery {
  41. /// Bootstrap endpoints maintained by root
  42. pub BootstrapEndpoints get(bootstrap_endpoints): Vec<Url>;
  43. /// Mapping of service providers' AccountIds to their AccountInfo
  44. pub AccountInfoByAccountId get(account_info_by_account_id): map T::AccountId => AccountInfo<T::BlockNumber>;
  45. /// Lifetime of an AccountInfo record in AccountInfoByAccountId map
  46. pub DefaultLifetime get(default_lifetime) config(): T::BlockNumber = T::BlockNumber::from(DEFAULT_LIFETIME);
  47. }
  48. }
  49. decl_event! {
  50. pub enum Event<T> where <T as system::Trait>::AccountId {
  51. AccountInfoUpdated(AccountId, IPNSIdentity),
  52. AccountInfoRemoved(AccountId),
  53. }
  54. }
  55. impl<T: Trait> Module<T> {
  56. pub fn remove_account_info(accountid: &T::AccountId) {
  57. if <AccountInfoByAccountId<T>>::exists(accountid) {
  58. <AccountInfoByAccountId<T>>::remove(accountid);
  59. Self::deposit_event(RawEvent::AccountInfoRemoved(accountid.clone()));
  60. }
  61. }
  62. pub fn is_account_info_expired(accountid: &T::AccountId) -> bool {
  63. !<AccountInfoByAccountId<T>>::exists(accountid)
  64. || <system::Module<T>>::block_number()
  65. > <AccountInfoByAccountId<T>>::get(accountid).expires_at
  66. }
  67. }
  68. decl_module! {
  69. pub struct Module<T: Trait> for enum Call where origin: T::Origin {
  70. fn deposit_event() = default;
  71. pub fn set_ipns_id(origin, id: Vec<u8>, lifetime: Option<T::BlockNumber>) {
  72. let sender = ensure_signed(origin)?;
  73. ensure!(T::Roles::is_role_account(&sender), "only role accounts can set ipns id");
  74. // TODO: ensure id is a valid base58 encoded IPNS identity
  75. let ttl = match lifetime {
  76. Some(value) => if value >= T::BlockNumber::from(MINIMUM_LIFETIME) {
  77. value
  78. } else {
  79. T::BlockNumber::from(MINIMUM_LIFETIME)
  80. },
  81. _ => Self::default_lifetime()
  82. };
  83. <AccountInfoByAccountId<T>>::insert(&sender, AccountInfo {
  84. identity: id.clone(),
  85. expires_at: <system::Module<T>>::block_number() + ttl,
  86. });
  87. Self::deposit_event(RawEvent::AccountInfoUpdated(sender.clone(), id.clone()));
  88. }
  89. pub fn unset_ipns_id(origin) {
  90. let sender = ensure_signed(origin)?;
  91. Self::remove_account_info(&sender);
  92. }
  93. // privileged methods
  94. pub fn set_default_lifetime(origin, lifetime: T::BlockNumber) {
  95. // although not strictly required to have an origin parameter and ensure_root
  96. // decl_module! macro takes care of it.. its required for unit tests to work correctly
  97. // otherwise it complains the method
  98. ensure_root(origin)?;
  99. ensure!(lifetime >= T::BlockNumber::from(MINIMUM_LIFETIME), "discovery: default lifetime must be gte minimum lifetime");
  100. <DefaultLifetime<T>>::put(lifetime);
  101. }
  102. pub fn set_bootstrap_endpoints(origin, endpoints: Vec<Vec<u8>>) {
  103. ensure_root(origin)?;
  104. BootstrapEndpoints::put(endpoints);
  105. }
  106. }
  107. }