Skip to content

update twin with myc pk #1037

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

Draft
wants to merge 2 commits into
base: development
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions clients/tfchain-client-go/twin.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,55 @@ func (s *Substrate) UpdateTwin(identity Identity, relay string, pk []byte) (uint

return s.GetTwinByPubKey(identity.PublicKey())
}

// SetTwinMyceliumPK sets the mycelium public key for a twin
func (s *Substrate) SetTwinMyceliumPK(identity Identity, twinID uint32, myceliumPK []byte) error {
cl, meta, err := s.GetClient()
if err != nil {
return err
}

c, err := types.NewCall(meta, "TfgridModule.set_twin_mycelium_pk", twinID, myceliumPK)
if err != nil {
return errors.Wrap(err, "failed to create call")
}

if _, err := s.Call(cl, meta, identity, c); err != nil {
return errors.Wrap(err, "failed to set twin mycelium pk")
}

return nil
}

// GetTwinByMyceliumPK gets a twin by mycelium public key
func (s *Substrate) GetTwinByMyceliumPK(myceliumPK string) (*Twin, error) {
cl, meta, err := s.GetClient()
if err != nil {
return nil, err
}

// must use encode to convert string to byte slice
bytes, err := Encode(myceliumPK)
if err != nil {
return nil, errors.Wrap(err, "substrate: encoding error building query arguments")
}

// First, get the twin ID from the mycelium PK mapping
key, err := types.CreateStorageKey(meta, "TfgridModule", "TwinByMyceliumPk", bytes, nil)
if err != nil {
return nil, errors.Wrap(err, "failed to create substrate query key")
}

var twinID types.U32
ok, err := cl.RPC.State.GetStorageLatest(key, &twinID)
if err != nil {
return nil, errors.Wrap(err, "failed to lookup twin by mycelium pk")
}

if !ok || twinID == 0 {
return nil, errors.Wrap(ErrNotFound, "twin not found for mycelium pk")
}

// Now get the full twin object using the twin ID
return s.GetTwin(uint32(twinID))
}
11 changes: 10 additions & 1 deletion clients/tfchain-client-js/lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ const {
} = require('./entity')
const {
createTwin, getTwin, getTwinIdByAccountId, updateTwin,
deleteTwin, addTwinEntity, deleteTwinEntity, listTwins
deleteTwin, addTwinEntity, deleteTwinEntity, listTwins,
setTwinMyceliumPK, getTwinByMyceliumPK
} = require('./twin')
const {
createFarm, getFarm, deleteFarm,
Expand Down Expand Up @@ -161,6 +162,14 @@ class Client {
return deleteTwinEntity(this, twinID, entityID, callback)
}

async setTwinMyceliumPK(twinId, myceliumPk, callback) {
return setTwinMyceliumPK(this, twinId, myceliumPk, callback)
}

async getTwinByMyceliumPK(myceliumPk) {
return getTwinByMyceliumPK(this, myceliumPk)
}

async createFarm(name, certificationType, publicIPs, callback) {
return createFarm(this, name, certificationType, publicIPs, callback)
}
Expand Down
26 changes: 25 additions & 1 deletion clients/tfchain-client-js/lib/twin.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,28 @@ async function deleteTwin (self, id, callback) {
.signAndSend(self.key, { nonce }, callback)
}

// setTwinMyceliumPK sets the mycelium public key for a twin
async function setTwinMyceliumPK (self, twinId, myceliumPk, callback) {
const setMyceliumPk = self.api.tx.tfgridModule.setTwinMyceliumPk(twinId, myceliumPk)
const nonce = await self.api.rpc.system.accountNextIndex(self.address)

return setMyceliumPk.signAndSend(self.key, { nonce }, callback)
}

// getTwinByMyceliumPK gets a twin by mycelium public key
async function getTwinByMyceliumPK (self, myceliumPk) {
// First, get the twin ID from the mycelium PK mapping
const twinIdResult = await self.api.query.tfgridModule.twinByMyceliumPk(myceliumPk)
const twinId = twinIdResult.toJSON()

if (!twinId || twinId === 0) {
throw Error(`Couldn't find a twin for mycelium pk: ${myceliumPk}`)
}

// Now get the full twin object using the twin ID
return getTwin(self, twinId)
}

module.exports = {
createTwin,
updateTwin,
Expand All @@ -100,5 +122,7 @@ module.exports = {
deleteTwin,
addTwinEntity,
deleteTwinEntity,
listTwins
listTwins,
setTwinMyceliumPK,
getTwinByMyceliumPK
}
20 changes: 20 additions & 0 deletions clients/tfchain-client-rs/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,26 @@ impl Client {
current::get_twin_id_by_account(self, account).await
}

// Sets mycelium public key for a twin and checks for success, blockhash is returned on success
pub async fn set_twin_mycelium_pk(
&self,
kp: &KeyPair,
twin_id: u32,
mycelium_pk: Vec<u8>,
) -> Result<Hash, Error> {
current::set_twin_mycelium_pk(self, kp, twin_id, mycelium_pk).await
}

// Gets a twin by mycelium public key and returns the full twin object
pub async fn get_twin_by_mycelium_pk(
&self,
mycelium_pk: Vec<u8>,
) -> Result<Option<Twin>, Error> {
// We pass a dummy keypair since it's not used in the implementation
let dummy_kp = KeyPair::Sr25519(sr25519::Pair::from_seed(&[0u8; 32]));
current::get_twin_by_mycelium_pk(self, &dummy_kp, mycelium_pk).await
}

pub async fn get_farm_by_id(&self, id: u32) -> Result<Option<Farm>, Error> {
current::get_farm_by_id(self, id).await
}
Expand Down
45 changes: 45 additions & 0 deletions clients/tfchain-client-rs/src/runtimes/current.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,48 @@ pub async fn get_balance(
.fetch(&current::storage().system().account(account))
.await?)
}

pub async fn set_twin_mycelium_pk(
cl: &Client,
kp: &KeyPair,
twin_id: u32,
mycelium_pk: Vec<u8>,
) -> Result<H256, Error> {
let set_mycelium_pk_tx = current::tx().tfgrid_module().set_twin_mycelium_pk(
twin_id,
BoundedVec(mycelium_pk),
);

let signer = kp.signer();

let set_mycelium_pk = cl
.api
.tx()
.sign_and_submit_then_watch_default(&set_mycelium_pk_tx, &signer)
.await?
.wait_for_finalized_success()
.await?;

Ok(set_mycelium_pk.block_hash())
}

pub async fn get_twin_by_mycelium_pk(
cl: &Client,
_kp: &KeyPair,
mycelium_pk: Vec<u8>,
) -> Result<Option<Twin>, Error> {
// Query the storage directly using the mycelium pk to get twin ID
let twin_id = cl
.api
.storage()
.at_latest()
.await?
.fetch(&current::storage().tfgrid_module().twin_by_mycelium_pk(BoundedVec(mycelium_pk)))
.await?;

if let Some(id) = twin_id {
get_twin_by_id(cl, id).await
} else {
Ok(None)
}
}
15 changes: 15 additions & 0 deletions substrate-node/pallets/pallet-tfgrid/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,17 @@ benchmarks! {
assert_last_event::<T>(Event::NodeUptimeReported(node_id, now, uptime).into());
}

// set_twin_mycelium_pk
set_twin_mycelium_pk {
let caller: T::AccountId = whitelisted_caller();
_create_twin::<T>(caller.clone());
let twin_id = 1;
let mycelium_pk = get_mycelium_pk_input(b"some_mycelium_pk");
}: _(RawOrigin::Signed(caller), twin_id, mycelium_pk.clone())
verify {
assert_eq!(TfgridModule::<T>::twin_by_mycelium_pk(&mycelium_pk), Some(twin_id));
}

// Calling the `impl_benchmark_test_suite` macro inside the `benchmarks`
// block will generate one #[test] function per benchmark
impl_benchmark_test_suite!(TfgridModule, crate::mock::new_test_ext(), crate::mock::TestRuntime)
Expand Down Expand Up @@ -1022,3 +1033,7 @@ pub(crate) fn get_pub_config_gw6_input(gw6_input: &[u8]) -> Gw6Input {
pub(crate) fn get_pub_config_domain_input(domain_input: &[u8]) -> DomainInput {
BoundedVec::try_from(domain_input.to_vec()).expect("Invalid domain input.")
}

// pub(crate) fn get_mycelium_pk_input(mycelium_pk_input: &[u8]) -> MyceliumPkInput {
// BoundedVec::try_from(mycelium_pk_input.to_vec()).expect("Invalid mycelium pk input.")
// }
35 changes: 35 additions & 0 deletions substrate-node/pallets/pallet-tfgrid/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ pub mod pallet {
// Concrete type for entity
pub type TfgridEntity<T> = types::Entity<AccountIdOf<T>, CityNameOf<T>, CountryNameOf<T>>;

pub type MyceliumPkInput = BoundedVec<u8, ConstU32<{ types::MAX_PK_LENGTH }>>;

#[pallet::storage]
#[pallet::getter(fn nodes)]
pub type Nodes<T> = StorageMap<_, Blake2_128Concat, u32, TfgridNode<T>, OptionQuery>;
Expand Down Expand Up @@ -263,6 +265,16 @@ pub mod pallet {
ValueQuery,
>;

#[pallet::storage]
#[pallet::getter(fn twin_by_mycelium_pk)]
pub type TwinByMyceliumPk<T: Config> = StorageMap<
_,
Blake2_128Concat,
MyceliumPkInput, // key is mycelium pk
u32, // value is twin id
OptionQuery, // returns None if pk not found
>;

#[pallet::config]
pub trait Config: frame_system::Config + pallet_timestamp::Config {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
Expand Down Expand Up @@ -411,6 +423,7 @@ pub mod pallet {
TwinEntityRemoved(u32, u32),
TwinDeleted(u32),
TwinAccountBounded(u32, T::AccountId),
TwinMyceliumPkSet(u32, MyceliumPkInput),

PricingPolicyStored(types::PricingPolicy<T::AccountId>),
// CertificationCodeStored(types::CertificationCodes),
Expand Down Expand Up @@ -1238,5 +1251,27 @@ pub mod pallet {
// Deprecated! Use index 40 for next extrinsic
// #[pallet::call_index(39)]
// #[pallet::weight(<T as Config>::WeightInfo::set_node_gpu_status())]

#[pallet::call_index(40)]
#[pallet::weight(<T as Config>::WeightInfo::set_twin_mycelium_pk())]
pub fn set_twin_mycelium_pk(
origin: OriginFor<T>,
twin_id: u32,
mycelium_pk: MyceliumPkInput,
) -> DispatchResultWithPostInfo {
let account_id = ensure_signed(origin)?;

// Ensure the caller owns this twin
let twin = Twins::<T>::get(twin_id).ok_or(Error::<T>::TwinNotExists)?;
ensure!(twin.account_id == account_id, Error::<T>::UnauthorizedToUpdateTwin);

// Store the mapping
TwinByMyceliumPk::<T>::insert(&mycelium_pk, twin_id);

// Emit event that mycelium-twin mapping is updated
Self::deposit_event(Event::TwinMyceliumPkSet(twin_id, mycelium_pk));

Ok(().into())
}
}
}
27 changes: 27 additions & 0 deletions substrate-node/pallets/pallet-tfgrid/src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ pub trait WeightInfo {
fn change_power_target() -> Weight;
fn bond_twin_account() -> Weight;
fn report_uptime_v2() -> Weight;
fn set_twin_mycelium_pk() -> Weight;
}

/// Weights for pallet_tfgrid using the Substrate node and recommended hardware.
Expand Down Expand Up @@ -548,6 +549,19 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
Weight::from_parts(18_465_000, 3919)
.saturating_add(T::DbWeight::get().reads(4_u64))
}
/// Storage: `TfgridModule::Twins` (r:1 w:0)
/// Proof: `TfgridModule::Twins` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `TfgridModule::TwinByMyceliumPk` (r:0 w:1)
/// Proof: `TfgridModule::TwinByMyceliumPk` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn set_twin_mycelium_pk() -> Weight {
// Proof Size summary in bytes:
// Measured: `387`
// Estimated: `3852`
// Minimum execution time: 11_743_000 picoseconds.
Weight::from_parts(12_053_000, 3852)
.saturating_add(T::DbWeight::get().reads(1_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
}

// For backwards compatibility and tests
Expand Down Expand Up @@ -1030,4 +1044,17 @@ impl WeightInfo for () {
Weight::from_parts(18_465_000, 3919)
.saturating_add(RocksDbWeight::get().reads(4_u64))
}
/// Storage: `TfgridModule::Twins` (r:1 w:0)
/// Proof: `TfgridModule::Twins` (`max_values`: None, `max_size`: None, mode: `Measured`)
/// Storage: `TfgridModule::TwinByMyceliumPk` (r:0 w:1)
/// Proof: `TfgridModule::TwinByMyceliumPk` (`max_values`: None, `max_size`: None, mode: `Measured`)
fn set_twin_mycelium_pk() -> Weight {
// Proof Size summary in bytes:
// Measured: `387`
// Estimated: `3852`
// Minimum execution time: 11_743_000 picoseconds.
Weight::from_parts(12_053_000, 3852)
.saturating_add(RocksDbWeight::get().reads(1_u64))
.saturating_add(RocksDbWeight::get().writes(1_u64))
}
}
Loading