// Copyright 2017-2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Substrate is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . //! Address type that is union of index and id for an account. #[cfg(feature = "std")] use std::fmt; use rstd::convert::TryInto; use crate::{Member, Decode, Encode, Input, Output}; /// An indices-aware address, which can be either a direct `AccountId` or /// an index. #[derive(PartialEq, Eq, Clone)] #[cfg_attr(feature = "std", derive(Debug, Hash))] pub enum Address where AccountId: Member, AccountIndex: Member, { /// It's an account ID (pubkey). Id(AccountId), /// It's an account index. Index(AccountIndex), } #[cfg(feature = "std")] impl fmt::Display for Address where AccountId: Member, AccountIndex: Member, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?}", self) } } impl From for Address where AccountId: Member, AccountIndex: Member, { fn from(a: AccountId) -> Self { Address::Id(a) } } fn need_more_than(a: T, b: T) -> Option { if a < b { Some(b) } else { None } } impl Decode for Address where AccountId: Member + Decode, AccountIndex: Member + Decode + PartialOrd + Ord + From + Copy, { fn decode(input: &mut I) -> Option { Some(match input.read_byte()? { x @ 0x00..=0xef => Address::Index(AccountIndex::from(x as u32)), 0xfc => Address::Index(AccountIndex::from( need_more_than(0xef, u16::decode(input)?)? as u32 )), 0xfd => Address::Index(AccountIndex::from( need_more_than(0xffff, u32::decode(input)?)? )), 0xfe => Address::Index( need_more_than(0xffffffffu32.into(), Decode::decode(input)?)? ), 0xff => Address::Id(Decode::decode(input)?), _ => return None, }) } } impl Encode for Address where AccountId: Member + Encode, AccountIndex: Member + Encode + PartialOrd + Ord + Copy + From + TryInto, { fn encode_to(&self, dest: &mut T) { match *self { Address::Id(ref i) => { dest.push_byte(255); dest.push(i); } Address::Index(i) => { let maybe_u32: Result = i.try_into(); if let Ok(x) = maybe_u32 { if x > 0xffff { dest.push_byte(253); dest.push(&x); } else if x >= 0xf0 { dest.push_byte(252); dest.push(&(x as u16)); } else { dest.push_byte(x as u8); } } else { dest.push_byte(254); dest.push(&i); } }, } } } impl Default for Address where AccountId: Member + Default, AccountIndex: Member, { fn default() -> Self { Address::Id(Default::default()) } } #[cfg(test)] mod tests { use crate::{Encode, Decode}; type Address = super::Address<[u8; 8], u32>; fn index(i: u32) -> Address { super::Address::Index(i) } fn id(i: [u8; 8]) -> Address { super::Address::Id(i) } fn compare(a: Option
, d: &[u8]) { if let Some(ref a) = a { assert_eq!(d, &a.encode()[..]); } assert_eq!(Address::decode(&mut &d[..]), a); } #[test] fn it_should_work() { compare(Some(index(2)), &[2][..]); compare(None, &[240][..]); compare(None, &[252, 239, 0][..]); compare(Some(index(240)), &[252, 240, 0][..]); compare(Some(index(304)), &[252, 48, 1][..]); compare(None, &[253, 255, 255, 0, 0][..]); compare(Some(index(0x10000)), &[253, 0, 0, 1, 0][..]); compare(Some(id([42, 69, 42, 69, 42, 69, 42, 69])), &[255, 42, 69, 42, 69, 42, 69, 42, 69][..]); } }