Skip to content
Snippets Groups Projects
Unverified Commit 03c7e58b authored by Shaopeng Wang's avatar Shaopeng Wang Committed by GitHub
Browse files

AuctionId bound check. (#229)

* AuctionId bound check.

* Remove unused code.

* Apply review suggestions; fmt.
parent b3281530
No related branches found
No related tags found
No related merge requests found
...@@ -17,9 +17,10 @@ use frame_support::{ ...@@ -17,9 +17,10 @@ use frame_support::{
use frame_system::{self as system, ensure_signed}; use frame_system::{self as system, ensure_signed};
use orml_traits::{Auction, AuctionHandler, AuctionInfo, Change}; use orml_traits::{Auction, AuctionHandler, AuctionInfo, Change};
use sp_runtime::{ use sp_runtime::{
traits::{AtLeast32Bit, MaybeSerializeDeserialize, Member, One, Zero}, traits::{AtLeast32Bit, Bounded, MaybeSerializeDeserialize, Member, One, Zero},
DispatchResult, DispatchError, DispatchResult,
}; };
use sp_std::result;
mod mock; mod mock;
mod tests; mod tests;
...@@ -31,7 +32,7 @@ pub trait Trait: frame_system::Trait { ...@@ -31,7 +32,7 @@ pub trait Trait: frame_system::Trait {
type Balance: Parameter + Member + AtLeast32Bit + Default + Copy + MaybeSerializeDeserialize; type Balance: Parameter + Member + AtLeast32Bit + Default + Copy + MaybeSerializeDeserialize;
/// The auction ID type /// The auction ID type
type AuctionId: Parameter + Member + AtLeast32Bit + Default + Copy + MaybeSerializeDeserialize; type AuctionId: Parameter + Member + AtLeast32Bit + Default + Copy + MaybeSerializeDeserialize + Bounded;
/// The `AuctionHandler` that allow custom bidding logic and handles auction result /// The `AuctionHandler` that allow custom bidding logic and handles auction result
type Handler: AuctionHandler<Self::AccountId, Self::Balance, Self::BlockNumber, Self::AuctionId>; type Handler: AuctionHandler<Self::AccountId, Self::Balance, Self::BlockNumber, Self::AuctionId>;
...@@ -144,6 +145,7 @@ decl_error! { ...@@ -144,6 +145,7 @@ decl_error! {
AuctionNotStarted, AuctionNotStarted,
BidNotAccepted, BidNotAccepted,
InvalidBidPrice, InvalidBidPrice,
NoAvailableAuctionId,
} }
} }
...@@ -180,16 +182,23 @@ impl<T: Trait> Auction<T::AccountId, T::BlockNumber> for Module<T> { ...@@ -180,16 +182,23 @@ impl<T: Trait> Auction<T::AccountId, T::BlockNumber> for Module<T> {
Ok(()) Ok(())
} }
fn new_auction(start: T::BlockNumber, end: Option<T::BlockNumber>) -> Self::AuctionId { fn new_auction(
start: T::BlockNumber,
end: Option<T::BlockNumber>,
) -> result::Result<Self::AuctionId, DispatchError> {
let auction = AuctionInfo { bid: None, start, end }; let auction = AuctionInfo { bid: None, start, end };
let auction_id = Self::auctions_index(); let auction_id = <AuctionsIndex<T>>::try_mutate(|n| -> result::Result<Self::AuctionId, DispatchError> {
<AuctionsIndex<T>>::mutate(|n| *n += Self::AuctionId::one()); let id = *n;
ensure!(id != Self::AuctionId::max_value(), Error::<T>::NoAvailableAuctionId);
*n += One::one();
Ok(id)
})?;
<Auctions<T>>::insert(auction_id, auction); <Auctions<T>>::insert(auction_id, auction);
if let Some(end_block) = end { if let Some(end_block) = end {
<AuctionEndTime<T>>::insert(&end_block, auction_id, ()); <AuctionEndTime<T>>::insert(&end_block, auction_id, ());
} }
auction_id Ok(auction_id)
} }
fn remove_auction(id: Self::AuctionId) { fn remove_auction(id: Self::AuctionId) {
......
...@@ -3,20 +3,20 @@ ...@@ -3,20 +3,20 @@
#![cfg(test)] #![cfg(test)]
use super::*; use super::*;
use frame_support::{assert_ok, traits::OnFinalize}; use frame_support::{assert_noop, assert_ok, traits::OnFinalize};
use mock::{AuctionModule, ExtBuilder, Runtime, ALICE}; use mock::*;
#[test] #[test]
fn new_auction_should_work() { fn new_auction_should_work() {
ExtBuilder::default().build().execute_with(|| { ExtBuilder::default().build().execute_with(|| {
assert_eq!(AuctionModule::new_auction(10, Some(100)), 0); assert_ok!(AuctionModule::new_auction(10, Some(100)), 0);
}); });
} }
#[test] #[test]
fn update_auction_should_work() { fn update_auction_should_work() {
ExtBuilder::default().build().execute_with(|| { ExtBuilder::default().build().execute_with(|| {
assert_eq!(AuctionModule::new_auction(10, Some(100)), 0); assert_ok!(AuctionModule::new_auction(10, Some(100)), 0);
assert_ok!(AuctionModule::update_auction( assert_ok!(AuctionModule::update_auction(
0, 0,
AuctionInfo { AuctionInfo {
...@@ -31,7 +31,7 @@ fn update_auction_should_work() { ...@@ -31,7 +31,7 @@ fn update_auction_should_work() {
#[test] #[test]
fn auction_info_should_work() { fn auction_info_should_work() {
ExtBuilder::default().build().execute_with(|| { ExtBuilder::default().build().execute_with(|| {
assert_eq!(AuctionModule::new_auction(10, Some(100)), 0); assert_ok!(AuctionModule::new_auction(10, Some(100)), 0);
assert_eq!( assert_eq!(
AuctionModule::auction_info(0), AuctionModule::auction_info(0),
Some(AuctionInfo { Some(AuctionInfo {
...@@ -46,7 +46,7 @@ fn auction_info_should_work() { ...@@ -46,7 +46,7 @@ fn auction_info_should_work() {
#[test] #[test]
fn bid_should_work() { fn bid_should_work() {
ExtBuilder::default().build().execute_with(|| { ExtBuilder::default().build().execute_with(|| {
assert_eq!(AuctionModule::new_auction(0, Some(100)), 0); assert_ok!(AuctionModule::new_auction(0, Some(100)), 0);
assert_ok!(AuctionModule::bid(Some(ALICE).into(), 0, 20)); assert_ok!(AuctionModule::bid(Some(ALICE).into(), 0, 20));
assert_eq!( assert_eq!(
AuctionModule::auction_info(0), AuctionModule::auction_info(0),
...@@ -62,7 +62,7 @@ fn bid_should_work() { ...@@ -62,7 +62,7 @@ fn bid_should_work() {
#[test] #[test]
fn bid_should_fail() { fn bid_should_fail() {
ExtBuilder::default().build().execute_with(|| { ExtBuilder::default().build().execute_with(|| {
assert_eq!(AuctionModule::new_auction(10, Some(100)), 0); assert_ok!(AuctionModule::new_auction(10, Some(100)), 0);
assert_eq!( assert_eq!(
AuctionModule::bid(Some(ALICE).into(), 0, 20), AuctionModule::bid(Some(ALICE).into(), 0, 20),
Err(Error::<Runtime>::AuctionNotStarted.into()) Err(Error::<Runtime>::AuctionNotStarted.into())
...@@ -73,7 +73,7 @@ fn bid_should_fail() { ...@@ -73,7 +73,7 @@ fn bid_should_fail() {
#[test] #[test]
fn remove_auction_should_work() { fn remove_auction_should_work() {
ExtBuilder::default().build().execute_with(|| { ExtBuilder::default().build().execute_with(|| {
assert_eq!(AuctionModule::new_auction(10, Some(100)), 0); assert_ok!(AuctionModule::new_auction(10, Some(100)), 0);
assert_eq!(AuctionModule::auctions_index(), 1); assert_eq!(AuctionModule::auctions_index(), 1);
assert_eq!(AuctionModule::auctions(0).is_some(), true); assert_eq!(AuctionModule::auctions(0).is_some(), true);
assert_eq!(AuctionModule::auction_end_time(100, 0), Some(())); assert_eq!(AuctionModule::auction_end_time(100, 0), Some(()));
...@@ -86,9 +86,9 @@ fn remove_auction_should_work() { ...@@ -86,9 +86,9 @@ fn remove_auction_should_work() {
#[test] #[test]
fn cleanup_auction_should_work() { fn cleanup_auction_should_work() {
ExtBuilder::default().build().execute_with(|| { ExtBuilder::default().build().execute_with(|| {
assert_eq!(AuctionModule::new_auction(10, Some(100)), 0); assert_ok!(AuctionModule::new_auction(10, Some(100)), 0);
assert_eq!(AuctionModule::auctions_index(), 1); assert_eq!(AuctionModule::auctions_index(), 1);
assert_eq!(AuctionModule::new_auction(10, Some(50)), 1); assert_ok!(AuctionModule::new_auction(10, Some(50)), 1);
assert_eq!(AuctionModule::auctions_index(), 2); assert_eq!(AuctionModule::auctions_index(), 2);
assert_eq!(AuctionModule::auctions(0).is_some(), true); assert_eq!(AuctionModule::auctions(0).is_some(), true);
assert_eq!(AuctionModule::auctions(1).is_some(), true); assert_eq!(AuctionModule::auctions(1).is_some(), true);
...@@ -112,3 +112,14 @@ fn cleanup_auction_should_work() { ...@@ -112,3 +112,14 @@ fn cleanup_auction_should_work() {
assert_eq!(<AuctionEndTime<Runtime>>::iter_prefix(100).count(), 0); assert_eq!(<AuctionEndTime<Runtime>>::iter_prefix(100).count(), 0);
}); });
} }
#[test]
fn cannot_add_new_auction_when_no_available_id() {
ExtBuilder::default().build().execute_with(|| {
<AuctionsIndex<Runtime>>::put(AuctionId::max_value());
assert_noop!(
AuctionModule::new_auction(0, None),
Error::<Runtime>::NoAvailableAuctionId
);
});
}
...@@ -2,12 +2,13 @@ use crate::Change; ...@@ -2,12 +2,13 @@ use crate::Change;
use codec::FullCodec; use codec::FullCodec;
use codec::{Decode, Encode}; use codec::{Decode, Encode};
use sp_runtime::{ use sp_runtime::{
traits::{AtLeast32Bit, MaybeSerializeDeserialize}, traits::{AtLeast32Bit, Bounded, MaybeSerializeDeserialize},
DispatchResult, RuntimeDebug, DispatchError, DispatchResult, RuntimeDebug,
}; };
use sp_std::{ use sp_std::{
cmp::{Eq, PartialEq}, cmp::{Eq, PartialEq},
fmt::Debug, fmt::Debug,
result,
}; };
/// Auction info. /// Auction info.
...@@ -25,7 +26,7 @@ pub struct AuctionInfo<AccountId, Balance, BlockNumber> { ...@@ -25,7 +26,7 @@ pub struct AuctionInfo<AccountId, Balance, BlockNumber> {
/// Abstraction over a simple auction system. /// Abstraction over a simple auction system.
pub trait Auction<AccountId, BlockNumber> { pub trait Auction<AccountId, BlockNumber> {
/// The id of an AuctionInfo /// The id of an AuctionInfo
type AuctionId: FullCodec + Default + Copy + Eq + PartialEq + MaybeSerializeDeserialize + Debug; type AuctionId: FullCodec + Default + Copy + Eq + PartialEq + MaybeSerializeDeserialize + Bounded + Debug;
/// The price to bid. /// The price to bid.
type Balance: AtLeast32Bit + FullCodec + Copy + MaybeSerializeDeserialize + Debug + Default; type Balance: AtLeast32Bit + FullCodec + Copy + MaybeSerializeDeserialize + Debug + Default;
...@@ -34,7 +35,7 @@ pub trait Auction<AccountId, BlockNumber> { ...@@ -34,7 +35,7 @@ pub trait Auction<AccountId, BlockNumber> {
/// Update the auction info of `id` with `info` /// Update the auction info of `id` with `info`
fn update_auction(id: Self::AuctionId, info: AuctionInfo<AccountId, Self::Balance, BlockNumber>) -> DispatchResult; fn update_auction(id: Self::AuctionId, info: AuctionInfo<AccountId, Self::Balance, BlockNumber>) -> DispatchResult;
/// Create new auction with specific startblock and endblock, return the id of the auction /// Create new auction with specific startblock and endblock, return the id of the auction
fn new_auction(start: BlockNumber, end: Option<BlockNumber>) -> Self::AuctionId; fn new_auction(start: BlockNumber, end: Option<BlockNumber>) -> result::Result<Self::AuctionId, DispatchError>;
/// Remove auction by `id` /// Remove auction by `id`
fn remove_auction(id: Self::AuctionId); fn remove_auction(id: Self::AuctionId);
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment