use core::marker::PhantomData; use fp_evm::ExitError; use frame_support::traits::{Currency, Get}; use pallet_evm::{BalanceConverter, PrecompileHandle, SubstrateBalance}; use precompile_utils::{EvmResult, prelude::UnboundedString}; use sp_core::{H256, U256}; use sp_runtime::traits::AccountIdConversion; use subtensor_runtime_common::{TaoBalance, Token}; use crate::{PrecompileExt, PrecompileHandleExt}; type SubtensorEconomicConstants = ( U256, U256, U256, U256, U256, U256, U256, U256, U256, U256, U256, U256, U256, ); type SubtensorSubnetConstants = ( u16, u16, u16, u16, u16, u16, u16, u16, u32, u32, u8, u16, u8, ); type SubtensorConsensusConstants = ( u16, u16, u16, U256, u16, u64, u16, bool, u64, u16, u16, u64, u64, ); type SubtensorRegistrationConstants = (u64, u64, u64, u16, u64, u16, u16, u64, u64, u64, u64); type SubtensorDelegationConstants = (u16, u16, u16, u16, u16, u16, u16, bool, bool); type SubtensorRateLimitConstants = (u64, u64, u64, u64, u64, u64, u64, u64, u64, u64, u64); type SubtensorProtocolConstants = ( u32, u32, u32, u128, u64, u64, u16, u8, u64, u64, u64, u64, U256, u32, U256, ); type BalancesConstants = (U256, u32, u32, u32); type ProxyConstants = (U256, U256, u32, u32, U256, U256); type SchedulerConstants = (u64, u64, u32); type DrandConstants = (UnboundedString, u64, u64, u64, u64, u64); type CrowdloanConstants = (U256, U256, u64, u64, u32, u32, H256); type SwapConstants = (u16, U256, U256, H256); pub(crate) type ProxyBalanceOf = <::Currency as Currency< ::AccountId, >>::Balance; pub struct RuntimeConfigurationPrecompile(PhantomData); impl PrecompileExt for RuntimeConfigurationPrecompile where R: frame_system::Config + pallet_admin_utils::Config + pallet_balances::Config + pallet_crowdloan::Config + pallet_drand::Config + pallet_evm::Config + pallet_evm_chain_id::Config + pallet_scheduler::Config + pallet_subtensor::Config + pallet_subtensor_proxy::Config + pallet_subtensor_swap::Config + pallet_timestamp::Config, R::AccountId: From<[u8; 32]> + Into<[u8; 32]>, frame_system::pallet_prelude::BlockNumberFor: TryInto, ::Moment: TryInto, ::Balance: Into, ProxyBalanceOf: Into, { const INDEX: u64 = 2066; } #[precompile_utils::precompile] impl RuntimeConfigurationPrecompile where R: frame_system::Config + pallet_admin_utils::Config + pallet_balances::Config + pallet_crowdloan::Config + pallet_drand::Config + pallet_evm::Config + pallet_evm_chain_id::Config + pallet_scheduler::Config + pallet_subtensor::Config + pallet_subtensor_proxy::Config + pallet_subtensor_swap::Config + pallet_timestamp::Config, R::AccountId: From<[u8; 32]> + Into<[u8; 32]>, frame_system::pallet_prelude::BlockNumberFor: TryInto, ::Moment: TryInto, ::Balance: Into, ProxyBalanceOf: Into, { #[precompile::public("getEvmChainId()")] #[precompile::view] fn get_evm_chain_id(handle: &mut impl PrecompileHandle) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_evm_chain_id::ChainId::::get()) } #[precompile::public("getTransactionRateLimit()")] #[precompile::view] fn get_transaction_rate_limit(handle: &mut impl PrecompileHandle) -> EvmResult { handle.record_db_reads::(1)?; Ok(pallet_subtensor::Pallet::::get_tx_rate_limit()) } #[precompile::public("getSubtensorEconomicConstants()")] #[precompile::view] fn get_subtensor_economic_constants( _handle: &mut impl PrecompileHandle, ) -> EvmResult { Ok(( tao_to_evm::(::InitialIssuance::get())?, tao_to_evm::( ::InitialRAORecycledForRegistration::get(), )?, tao_to_evm::(::InitialBurn::get())?, tao_to_evm::(::InitialMinBurn::get())?, tao_to_evm::(::InitialMaxBurn::get())?, tao_to_evm::(::InitialMinStake::get())?, tao_to_evm::(::InitialMinTransfer::get())?, tao_to_evm::(::MinBurnUpperBound::get())?, tao_to_evm::(::MaxBurnLowerBound::get())?, tao_to_evm::(::InitialNetworkMinLockCost::get())?, tao_to_evm::(::KeySwapCost::get())?, tao_to_evm::(::KeySwapOnSubnetCost::get())?, tao_to_evm::(pallet_subtensor::pallet::MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP)?, )) } #[precompile::public("getSubtensorSubnetConstants()")] #[precompile::view] fn get_subtensor_subnet_constants( _handle: &mut impl PrecompileHandle, ) -> EvmResult { Ok(( ::InitialTempo::get(), ::MinTempo::get(), ::MaxTempo::get(), ::InitialMinAllowedUids::get(), ::InitialMaxAllowedUids::get(), ::InitialMaxAllowedValidators::get(), ::InitialImmunityPeriod::get(), ::InitialActivityCutoff::get(), ::MinActivityCutoffFactorMilli::get(), ::MaxActivityCutoffFactorMilli::get(), ::MaxImmuneUidsPercentage::get().deconstruct(), ::InitialSubnetOwnerCut::get(), ::InitialMaxEpochsPerBlock::get(), )) } #[precompile::public("getSubtensorConsensusConstants()")] #[precompile::view] fn get_subtensor_consensus_constants( _handle: &mut impl PrecompileHandle, ) -> EvmResult { Ok(( ::InitialMinAllowedWeights::get(), ::InitialEmissionValue::get(), ::InitialRho::get(), signed_i16_word(::InitialAlphaSigmoidSteepness::get()), ::InitialKappa::get(), ::InitialBondsMovingAverage::get(), ::InitialBondsPenalty::get(), ::InitialBondsResetOn::get(), ::InitialValidatorPruneLen::get(), ::InitialScalingLawPower::get(), ::InitialPruningScore::get(), ::InitialWeightsVersionKey::get(), ::InitialTaoWeight::get(), )) } #[precompile::public("getSubtensorRegistrationConstants()")] #[precompile::view] fn get_subtensor_registration_constants( _handle: &mut impl PrecompileHandle, ) -> EvmResult { Ok(( ::InitialDifficulty::get(), ::InitialMinDifficulty::get(), ::InitialMaxDifficulty::get(), ::InitialAdjustmentInterval::get(), ::InitialAdjustmentAlpha::get(), ::InitialMaxRegistrationsPerBlock::get(), ::InitialTargetRegistrationsPerInterval::get(), ::InitialNetworkRateLimit::get(), ::InitialNetworkImmunityPeriod::get(), ::InitialNetworkLockReductionInterval::get(), ::InitialEmaPriceHalvingPeriod::get(), )) } #[precompile::public("getSubtensorDelegationConstants()")] #[precompile::view] fn get_subtensor_delegation_constants( _handle: &mut impl PrecompileHandle, ) -> EvmResult { Ok(( ::InitialDefaultDelegateTake::get(), ::InitialMinDelegateTake::get(), ::InitialDefaultChildKeyTake::get(), ::InitialMinChildKeyTake::get(), ::InitialMaxChildKeyTake::get(), ::AlphaHigh::get(), ::AlphaLow::get(), ::LiquidAlphaOn::get(), ::Yuma3On::get(), )) } #[precompile::public("getSubtensorRateLimitConstants()")] #[precompile::view] fn get_subtensor_rate_limit_constants( _handle: &mut impl PrecompileHandle, ) -> EvmResult { Ok(( ::InitialServingRateLimit::get(), ::InitialTxRateLimit::get(), ::InitialTxDelegateTakeRateLimit::get(), ::InitialTxChildKeyTakeRateLimit::get(), ::EvmKeyAssociateRateLimit::get(), block_to_u64( ::InitialColdkeySwapAnnouncementDelay::get(), )?, block_to_u64( ::InitialColdkeySwapReannouncementDelay::get(), )?, block_to_u64( ::InitialDissolveNetworkScheduleDuration::get(), )?, ::InitialStartCallDelay::get(), ::HotkeySwapOnSubnetInterval::get(), block_to_u64( ::LeaseDividendsDistributionInterval::get(), )?, )) } #[precompile::public("getSubtensorProtocolConstants()")] #[precompile::view] fn get_subtensor_protocol_constants( _handle: &mut impl PrecompileHandle, ) -> EvmResult { Ok(( pallet_subtensor::MAX_CRV3_COMMIT_SIZE_BYTES, pallet_subtensor::MAX_ASSOCIATED_UIDS_PER_EVM_ADDRESS, pallet_subtensor::MAX_COLDKEY_COLLATERAL_HOTKEYS, pallet_subtensor::ACCOUNT_FLAGS_ACCEPT_LOCKED_ALPHA, pallet_subtensor::pallet::MIN_COMMIT_REVEAL_PEROIDS, pallet_subtensor::pallet::MAX_COMMIT_REVEAL_PEROIDS, pallet_subtensor::subnets::mechanism::GLOBAL_MAX_SUBNET_COUNT, pallet_subtensor::subnets::mechanism::MAX_MECHANISM_COUNT_PER_SUBNET, pallet_subtensor::utils::voting_power::VOTING_POWER_DISABLE_GRACE_PERIOD_BLOCKS, pallet_subtensor::utils::voting_power::MAX_VOTING_POWER_EMA_ALPHA, pallet_subtensor::Pallet::::EMISSION_BAR_UPDATE_INTERVAL, pallet_subtensor::staking::lock::ONE_YEAR, tao_u64_to_evm::(pallet_subtensor::staking::lock::LOCK_STATE_ZERO_THRESHOLD)?, pallet_subtensor::pallet::INITIAL_ACTIVITY_CUTOFF_FACTOR_MILLI, tao_u64_to_evm::(pallet_subtensor::coinbase::tao::MAX_TAO_ISSUANCE)?, )) } #[precompile::public("getSubtensorSystemAccounts()")] #[precompile::view] fn get_subtensor_system_accounts( _handle: &mut impl PrecompileHandle, ) -> EvmResult<(H256, H256)> { Ok(( pallet_account::(::SubtensorPalletId::get()), pallet_account::(::BurnAccountId::get()), )) } #[precompile::public("getBalancesConstants()")] #[precompile::view] fn get_balances_constants(_handle: &mut impl PrecompileHandle) -> EvmResult { Ok(( balance_to_evm::(::ExistentialDeposit::get())?, ::MaxLocks::get(), ::MaxReserves::get(), ::MaxFreezes::get(), )) } #[precompile::public("getProxyConstants()")] #[precompile::view] fn get_proxy_constants(_handle: &mut impl PrecompileHandle) -> EvmResult { Ok(( balance_to_evm::(::ProxyDepositBase::get())?, balance_to_evm::( ::ProxyDepositFactor::get(), )?, ::MaxProxies::get(), ::MaxPending::get(), balance_to_evm::( ::AnnouncementDepositBase::get(), )?, balance_to_evm::( ::AnnouncementDepositFactor::get(), )?, )) } #[precompile::public("getSchedulerConstants()")] #[precompile::view] fn get_scheduler_constants( _handle: &mut impl PrecompileHandle, ) -> EvmResult { let maximum_weight = ::MaximumWeight::get(); Ok(( maximum_weight.ref_time(), maximum_weight.proof_size(), ::MaxScheduledPerBlock::get(), )) } #[precompile::public("getDrandConstants()")] #[precompile::view] fn get_drand_constants(_handle: &mut impl PrecompileHandle) -> EvmResult { Ok(( UnboundedString::from(pallet_drand::QUICKNET_CHAIN_HASH), ::UnsignedPriority::get(), ::HttpFetchTimeout::get(), pallet_drand::MAX_PULSES_TO_FETCH, pallet_drand::MAX_KEPT_PULSES, pallet_drand::MAX_REMOVED_PULSES, )) } #[precompile::public("getCrowdloanConstants()")] #[precompile::view] fn get_crowdloan_constants( _handle: &mut impl PrecompileHandle, ) -> EvmResult { Ok(( tao_to_evm::(::MinimumDeposit::get())?, tao_to_evm::(::AbsoluteMinimumContribution::get())?, block_to_u64(::MinimumBlockDuration::get())?, block_to_u64(::MaximumBlockDuration::get())?, ::RefundContributorsLimit::get(), ::MaxContributors::get(), pallet_account::(::PalletId::get()), )) } #[precompile::public("getSwapConstants()")] #[precompile::view] fn get_swap_constants(_handle: &mut impl PrecompileHandle) -> EvmResult { Ok(( ::MaxFeeRate::get(), tao_u64_to_evm::(::MinimumLiquidity::get())?, tao_u64_to_evm::(::MinimumReserve::get().get())?, pallet_account::(::ProtocolId::get()), )) } #[precompile::public("getTimestampConstants()")] #[precompile::view] fn get_timestamp_constants(_handle: &mut impl PrecompileHandle) -> EvmResult { ::MinimumPeriod::get() .try_into() .map_err(|_| ExitError::InvalidRange.into()) } #[precompile::public("getAdminConstants()")] #[precompile::view] fn get_admin_constants(_handle: &mut impl PrecompileHandle) -> EvmResult { Ok(::MaxAuthorities::get()) } } fn tao_to_evm(value: TaoBalance) -> EvmResult where R: pallet_evm::Config, { tao_u64_to_evm::(value.to_u64()) } fn tao_u64_to_evm(value: u64) -> EvmResult where R: pallet_evm::Config, { let value: SubstrateBalance = value.into(); R::BalanceConverter::into_evm_balance(value) .map(|amount| amount.into_u256()) .ok_or_else(|| ExitError::InvalidRange.into()) } fn balance_to_evm(value: Balance) -> EvmResult where R: pallet_evm::Config, Balance: Into, { let value = SubstrateBalance::new(value.into()); R::BalanceConverter::into_evm_balance(value) .map(|amount| amount.into_u256()) .ok_or_else(|| ExitError::InvalidRange.into()) } fn block_to_u64>(block: Block) -> EvmResult { block.try_into().map_err(|_| ExitError::InvalidRange.into()) } fn pallet_account(pallet_id: frame_support::PalletId) -> H256 where R: frame_system::Config, R::AccountId: Into<[u8; 32]>, { let account: R::AccountId = pallet_id.into_account_truncating(); H256::from(>::into(account)) } fn signed_i16_word(value: i16) -> U256 { let mut encoded = [if value.is_negative() { 0xff } else { 0 }; 32]; encoded[30..].copy_from_slice(&value.to_be_bytes()); U256::from_big_endian(&encoded) } #[cfg(test)] mod tests { #![allow(clippy::unwrap_used)] use super::*; use crate::mock::{Runtime, addr_from_index, new_test_ext, precompiles, selector_u32}; use precompile_utils::{ prelude::RuntimeHelper, solidity::{Codec, encode_return_value, encode_with_selector}, testing::PrecompileTesterExt, }; fn assert_view(signature: &str, expected: Output) { let precompiles = precompiles::>(); precompiles .prepare_test( addr_from_index(1), addr_from_index(RuntimeConfigurationPrecompile::::INDEX), encode_with_selector(selector_u32(signature), ()), ) .with_static_call(true) .execute_returns_raw(encode_return_value(expected)); } #[test] fn address_storage_selectors_and_values_are_stable() { new_test_ext().execute_with(|| { assert_eq!(RuntimeConfigurationPrecompile::::INDEX, 2066); pallet_evm_chain_id::ChainId::::put(9_999u64); pallet_subtensor::TxRateLimit::::put(77u64); let precompiles = precompiles::>(); let caller = addr_from_index(1); let address = addr_from_index(2066); let read_cost = RuntimeHelper::::db_read_gas_cost(); precompiles .prepare_test( caller, address, encode_with_selector(selector_u32("getEvmChainId()"), ()), ) .with_static_call(true) .expect_cost(read_cost) .execute_returns_raw(encode_return_value(9_999u64)); precompiles .prepare_test( caller, address, encode_with_selector(selector_u32("getTransactionRateLimit()"), ()), ) .with_static_call(true) .expect_cost(read_cost) .execute_returns_raw(encode_return_value(77u64)); }); } #[test] fn subtensor_constant_views_return_authoritative_runtime_values() { new_test_ext().execute_with(|| { assert_view( "getSubtensorEconomicConstants()", ( tao_to_evm::(::InitialIssuance::get()).unwrap(), tao_to_evm::(::InitialRAORecycledForRegistration::get()) .unwrap(), tao_to_evm::(::InitialBurn::get()).unwrap(), tao_to_evm::(::InitialMinBurn::get()).unwrap(), tao_to_evm::(::InitialMaxBurn::get()).unwrap(), tao_to_evm::(::InitialMinStake::get()).unwrap(), tao_to_evm::(::InitialMinTransfer::get()).unwrap(), tao_to_evm::(::MinBurnUpperBound::get()).unwrap(), tao_to_evm::(::MaxBurnLowerBound::get()).unwrap(), tao_to_evm::(::InitialNetworkMinLockCost::get()).unwrap(), tao_to_evm::(::KeySwapCost::get()).unwrap(), tao_to_evm::(::KeySwapOnSubnetCost::get()).unwrap(), tao_to_evm::( pallet_subtensor::pallet::MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP, ) .unwrap(), ), ); assert_view( "getSubtensorSubnetConstants()", ( ::InitialTempo::get(), ::MinTempo::get(), ::MaxTempo::get(), ::InitialMinAllowedUids::get(), ::InitialMaxAllowedUids::get(), ::InitialMaxAllowedValidators::get(), ::InitialImmunityPeriod::get(), ::InitialActivityCutoff::get(), ::MinActivityCutoffFactorMilli::get(), ::MaxActivityCutoffFactorMilli::get(), ::MaxImmuneUidsPercentage::get().deconstruct(), ::InitialSubnetOwnerCut::get(), ::InitialMaxEpochsPerBlock::get(), ), ); assert_view( "getSubtensorConsensusConstants()", ( ::InitialMinAllowedWeights::get(), ::InitialEmissionValue::get(), ::InitialRho::get(), signed_i16_word(::InitialAlphaSigmoidSteepness::get()), ::InitialKappa::get(), ::InitialBondsMovingAverage::get(), ::InitialBondsPenalty::get(), ::InitialBondsResetOn::get(), ::InitialValidatorPruneLen::get(), ::InitialScalingLawPower::get(), ::InitialPruningScore::get(), ::InitialWeightsVersionKey::get(), ::InitialTaoWeight::get(), ), ); assert_view( "getSubtensorRegistrationConstants()", ( ::InitialDifficulty::get(), ::InitialMinDifficulty::get(), ::InitialMaxDifficulty::get(), ::InitialAdjustmentInterval::get(), ::InitialAdjustmentAlpha::get(), ::InitialMaxRegistrationsPerBlock::get(), ::InitialTargetRegistrationsPerInterval::get(), ::InitialNetworkRateLimit::get(), ::InitialNetworkImmunityPeriod::get(), ::InitialNetworkLockReductionInterval::get(), ::InitialEmaPriceHalvingPeriod::get(), ), ); assert_view( "getSubtensorDelegationConstants()", ( ::InitialDefaultDelegateTake::get(), ::InitialMinDelegateTake::get(), ::InitialDefaultChildKeyTake::get(), ::InitialMinChildKeyTake::get(), ::InitialMaxChildKeyTake::get(), ::AlphaHigh::get(), ::AlphaLow::get(), ::LiquidAlphaOn::get(), ::Yuma3On::get(), ), ); assert_view( "getSubtensorRateLimitConstants()", ( ::InitialServingRateLimit::get(), ::InitialTxRateLimit::get(), ::InitialTxDelegateTakeRateLimit::get(), ::InitialTxChildKeyTakeRateLimit::get(), ::EvmKeyAssociateRateLimit::get(), block_to_u64(::InitialColdkeySwapAnnouncementDelay::get()).unwrap(), block_to_u64(::InitialColdkeySwapReannouncementDelay::get()).unwrap(), block_to_u64(::InitialDissolveNetworkScheduleDuration::get()).unwrap(), ::InitialStartCallDelay::get(), ::HotkeySwapOnSubnetInterval::get(), block_to_u64(::LeaseDividendsDistributionInterval::get()).unwrap(), ), ); assert_view( "getSubtensorProtocolConstants()", ( pallet_subtensor::MAX_CRV3_COMMIT_SIZE_BYTES, pallet_subtensor::MAX_ASSOCIATED_UIDS_PER_EVM_ADDRESS, pallet_subtensor::MAX_COLDKEY_COLLATERAL_HOTKEYS, pallet_subtensor::ACCOUNT_FLAGS_ACCEPT_LOCKED_ALPHA, pallet_subtensor::pallet::MIN_COMMIT_REVEAL_PEROIDS, pallet_subtensor::pallet::MAX_COMMIT_REVEAL_PEROIDS, pallet_subtensor::subnets::mechanism::GLOBAL_MAX_SUBNET_COUNT, pallet_subtensor::subnets::mechanism::MAX_MECHANISM_COUNT_PER_SUBNET, pallet_subtensor::utils::voting_power::VOTING_POWER_DISABLE_GRACE_PERIOD_BLOCKS, pallet_subtensor::utils::voting_power::MAX_VOTING_POWER_EMA_ALPHA, pallet_subtensor::Pallet::::EMISSION_BAR_UPDATE_INTERVAL, pallet_subtensor::staking::lock::ONE_YEAR, tao_u64_to_evm::( pallet_subtensor::staking::lock::LOCK_STATE_ZERO_THRESHOLD, ) .unwrap(), pallet_subtensor::pallet::INITIAL_ACTIVITY_CUTOFF_FACTOR_MILLI, tao_u64_to_evm::(pallet_subtensor::coinbase::tao::MAX_TAO_ISSUANCE) .unwrap(), ), ); assert_view( "getSubtensorSystemAccounts()", ( pallet_account::(::SubtensorPalletId::get()), pallet_account::(::BurnAccountId::get()), ), ); }); } #[test] fn other_pallet_constant_views_return_authoritative_runtime_values() { new_test_ext().execute_with(|| { assert_view( "getBalancesConstants()", ( balance_to_evm::( ::ExistentialDeposit::get(), ) .unwrap(), <::MaxLocks as Get>::get(), <::MaxReserves as Get>::get(), ::MaxFreezes::get(), ), ); assert_view( "getProxyConstants()", ( balance_to_evm::( ::ProxyDepositBase::get(), ) .unwrap(), balance_to_evm::( ::ProxyDepositFactor::get(), ) .unwrap(), ::MaxProxies::get(), ::MaxPending::get(), balance_to_evm::( ::AnnouncementDepositBase::get(), ) .unwrap(), balance_to_evm::( ::AnnouncementDepositFactor::get( ), ) .unwrap(), ), ); let maximum_weight = ::MaximumWeight::get(); assert_view( "getSchedulerConstants()", ( maximum_weight.ref_time(), maximum_weight.proof_size(), ::MaxScheduledPerBlock::get(), ), ); assert_view( "getDrandConstants()", ( UnboundedString::from(pallet_drand::QUICKNET_CHAIN_HASH), <::UnsignedPriority as Get>::get(), <::HttpFetchTimeout as Get>::get(), pallet_drand::MAX_PULSES_TO_FETCH, pallet_drand::MAX_KEPT_PULSES, pallet_drand::MAX_REMOVED_PULSES, ), ); assert_view( "getCrowdloanConstants()", ( tao_to_evm::( ::MinimumDeposit::get(), ) .unwrap(), tao_to_evm::( ::AbsoluteMinimumContribution::get(), ) .unwrap(), block_to_u64( ::MinimumBlockDuration::get(), ) .unwrap(), block_to_u64( ::MaximumBlockDuration::get(), ) .unwrap(), ::RefundContributorsLimit::get(), ::MaxContributors::get(), pallet_account::( ::PalletId::get(), ), ), ); assert_view( "getSwapConstants()", ( ::MaxFeeRate::get(), tao_u64_to_evm::( ::MinimumLiquidity::get(), ) .unwrap(), tao_u64_to_evm::( ::MinimumReserve::get().get(), ) .unwrap(), pallet_account::( ::ProtocolId::get(), ), ), ); assert_view( "getTimestampConstants()", ::MinimumPeriod::get(), ); assert_view( "getAdminConstants()", ::MaxAuthorities::get(), ); }); } #[test] fn signed_i16_constants_use_solidity_sign_extension() { assert_eq!(signed_i16_word(1), U256::one()); assert_eq!(signed_i16_word(-1), U256::from_big_endian(&[0xff; 32])); assert_eq!( signed_i16_word(i16::MIN), U256::from_big_endian(&{ let mut word = [0xff; 32]; word[30..].copy_from_slice(&i16::MIN.to_be_bytes()); word }) ); } }