diff --git a/.gitignore b/.gitignore
index 4302acbf9f0799cd3c6b4d57506fdc748964dc21..4e2d59749d649ebe8c76a2e98aabdd0f0ecf41fb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,4 +10,4 @@ Cargo.lock
 **/*.rs.bk
 
 # Intentional not commiting this file to allow this repo to be added as a submodule
-Cargo.toml
+/Cargo.toml
diff --git a/utilities/Cargo.toml b/utilities/Cargo.toml
index 93553ec7f882b1ada7cbed4842d9d5ecd2649b67..622c43e1ec874b8580859a2afc72f455861d7a0b 100644
--- a/utilities/Cargo.toml
+++ b/utilities/Cargo.toml
@@ -13,6 +13,9 @@ system = { package = "srml-system", git = "https://github.com/paritytech/substra
 runtime_io = { package = "sr-io", git = "https://github.com/paritytech/substrate.git", default-features = false }
 rstd = { package = "sr-std", git = "https://github.com/paritytech/substrate.git", default-features = false }
 
+[dev-dependencies]
+primitives = { package = "substrate-primitives",  git = "https://github.com/paritytech/substrate.git", default-features = false }
+
 [features]
 default = ["std"]
 std = [
diff --git a/utilities/src/lib.rs b/utilities/src/lib.rs
index c6040563021d03b06a8fd5d200ea4e542c8c4779..6b864cc0748b4ff660f614de5dfc7b822e8af9c4 100644
--- a/utilities/src/lib.rs
+++ b/utilities/src/lib.rs
@@ -1,15 +1,5 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 
-pub fn add(a: u32, b: u32) -> u32 {
-	a + b
-}
+pub mod linked_item;
 
-#[cfg(test)]
-mod tests {
-	use super::*;
-
-	#[test]
-	fn it_works() {
-		assert_eq!(add(1, 1), 2);
-	}
-}
+pub use linked_item::{LinkedItem, LinkedList};
diff --git a/utilities/src/linked_item.rs b/utilities/src/linked_item.rs
new file mode 100644
index 0000000000000000000000000000000000000000..348fd82092d0ebebe4053d2826664bc7c535b242
--- /dev/null
+++ b/utilities/src/linked_item.rs
@@ -0,0 +1,290 @@
+use codec::{Decode, Encode};
+use sr_primitives::{traits::Member, RuntimeDebug};
+use support::{Parameter, StorageMap};
+
+#[derive(RuntimeDebug, PartialEq, Eq, Encode, Decode)]
+pub struct LinkedItem<Item> {
+	pub prev: Option<Item>,
+	pub next: Option<Item>,
+}
+
+pub struct LinkedList<Storage, Key, Item>(rstd::marker::PhantomData<(Storage, Key, Item)>);
+
+impl<Storage, Key, Value> LinkedList<Storage, Key, Value>
+where
+	Value: Parameter + Member + Copy,
+	Key: Parameter,
+	Storage: StorageMap<(Key, Option<Value>), LinkedItem<Value>, Query = Option<LinkedItem<Value>>>,
+{
+	fn read_head(key: &Key) -> LinkedItem<Value> {
+		Self::read(key, None)
+	}
+
+	fn write_head(account: &Key, item: LinkedItem<Value>) {
+		Self::write(account, None, item);
+	}
+
+	fn read(key: &Key, value: Option<Value>) -> LinkedItem<Value> {
+		Storage::get(&(key.clone(), value)).unwrap_or_else(|| LinkedItem { prev: None, next: None })
+	}
+
+	fn write(key: &Key, value: Option<Value>, item: LinkedItem<Value>) {
+		Storage::insert(&(key.clone(), value), item);
+	}
+
+	pub fn append(key: &Key, value: Value) {
+		let head = Self::read_head(key);
+		let new_head = LinkedItem {
+			prev: Some(value),
+			next: head.next,
+		};
+
+		Self::write_head(key, new_head);
+
+		let prev = Self::read(key, head.prev);
+		let new_prev = LinkedItem {
+			prev: prev.prev,
+			next: Some(value),
+		};
+		Self::write(key, head.prev, new_prev);
+
+		let item = LinkedItem {
+			prev: head.prev,
+			next: None,
+		};
+		Self::write(key, Some(value), item);
+	}
+
+	pub fn remove(key: &Key, value: Value) {
+		if let Some(item) = Storage::take(&(key.clone(), Some(value))) {
+			let prev = Self::read(key, item.prev);
+			let new_prev = LinkedItem {
+				prev: prev.prev,
+				next: item.next,
+			};
+
+			Self::write(key, item.prev, new_prev);
+
+			let next = Self::read(key, item.next);
+			let new_next = LinkedItem {
+				prev: item.prev,
+				next: next.next,
+			};
+
+			Self::write(key, item.next, new_next);
+		}
+	}
+}
+
+#[cfg(test)]
+mod tests {
+	use super::*;
+	use primitives::H256;
+	use sr_primitives::{testing::Header, traits::IdentityLookup, Perbill};
+	use support::{decl_module, decl_storage, impl_outer_origin, parameter_types, StorageMap};
+
+	type Key = u64;
+	type Value = u32;
+	pub trait Trait: system::Trait {}
+
+	type TestLinkedItem = LinkedItem<Value>;
+
+	decl_storage! {
+		trait Store for Module<T: Trait> as Test {
+			pub TestItem get(linked_list): map (Key, Option<Value>) => Option<TestLinkedItem>;
+		}
+	}
+
+	decl_module! {
+		pub struct Module<T: Trait> for enum Call where origin: T::Origin {
+		}
+	}
+
+	impl_outer_origin! {
+		pub enum Origin for Test {}
+	}
+
+	// For testing the module, we construct most of a mock runtime. This means
+	// first constructing a configuration type (`Test`) which `impl`s each of the
+	// configuration traits of modules we want to use.
+	#[derive(Clone, Eq, PartialEq, Debug)]
+	pub struct Test;
+	parameter_types! {
+		pub const BlockHashCount: u64 = 250;
+		pub const MaximumBlockWeight: u32 = 1024;
+		pub const MaximumBlockLength: u32 = 2 * 1024;
+		pub const AvailableBlockRatio: Perbill = Perbill::one();
+	}
+	impl system::Trait for Test {
+		type Origin = Origin;
+		type Index = u64;
+		type BlockNumber = u64;
+		type Call = ();
+		type Hash = H256;
+		type Hashing = ::sr_primitives::traits::BlakeTwo256;
+		type AccountId = u64;
+		type Lookup = IdentityLookup<Self::AccountId>;
+		type Header = Header;
+		type Event = ();
+		type BlockHashCount = BlockHashCount;
+		type MaximumBlockWeight = MaximumBlockWeight;
+		type MaximumBlockLength = MaximumBlockLength;
+		type AvailableBlockRatio = AvailableBlockRatio;
+		type Version = ();
+	}
+
+	type TestLinkedList = LinkedList<TestItem, Key, Value>;
+
+	pub fn new_test_ext() -> runtime_io::TestExternalities {
+		system::GenesisConfig::default().build_storage::<Test>().unwrap().into()
+	}
+
+	#[test]
+	fn linked_list_can_append_values() {
+		new_test_ext().execute_with(|| {
+			TestLinkedList::append(&0, 1);
+
+			assert_eq!(
+				TestItem::get(&(0, None)),
+				Some(TestLinkedItem {
+					prev: Some(1),
+					next: Some(1),
+				})
+			);
+
+			assert_eq!(
+				TestItem::get(&(0, Some(1))),
+				Some(TestLinkedItem { prev: None, next: None })
+			);
+
+			TestLinkedList::append(&0, 2);
+
+			assert_eq!(
+				TestItem::get(&(0, None)),
+				Some(TestLinkedItem {
+					prev: Some(2),
+					next: Some(1),
+				})
+			);
+
+			assert_eq!(
+				TestItem::get(&(0, Some(1))),
+				Some(TestLinkedItem {
+					prev: None,
+					next: Some(2),
+				})
+			);
+
+			assert_eq!(
+				TestItem::get(&(0, Some(2))),
+				Some(TestLinkedItem {
+					prev: Some(1),
+					next: None,
+				})
+			);
+
+			TestLinkedList::append(&0, 3);
+
+			assert_eq!(
+				TestItem::get(&(0, None)),
+				Some(TestLinkedItem {
+					prev: Some(3),
+					next: Some(1),
+				})
+			);
+
+			assert_eq!(
+				TestItem::get(&(0, Some(1))),
+				Some(TestLinkedItem {
+					prev: None,
+					next: Some(2),
+				})
+			);
+
+			assert_eq!(
+				TestItem::get(&(0, Some(2))),
+				Some(TestLinkedItem {
+					prev: Some(1),
+					next: Some(3),
+				})
+			);
+
+			assert_eq!(
+				TestItem::get(&(0, Some(3))),
+				Some(TestLinkedItem {
+					prev: Some(2),
+					next: None,
+				})
+			);
+		});
+	}
+
+	#[test]
+	fn linked_list_can_remove_values() {
+		new_test_ext().execute_with(|| {
+			TestLinkedList::append(&0, 1);
+			TestLinkedList::append(&0, 2);
+			TestLinkedList::append(&0, 3);
+
+			TestLinkedList::remove(&0, 2);
+
+			assert_eq!(
+				TestItem::get(&(0, None)),
+				Some(TestLinkedItem {
+					prev: Some(3),
+					next: Some(1),
+				})
+			);
+
+			assert_eq!(
+				TestItem::get(&(0, Some(1))),
+				Some(TestLinkedItem {
+					prev: None,
+					next: Some(3),
+				})
+			);
+
+			assert_eq!(TestItem::get(&(0, Some(2))), None);
+
+			assert_eq!(
+				TestItem::get(&(0, Some(3))),
+				Some(TestLinkedItem {
+					prev: Some(1),
+					next: None,
+				})
+			);
+
+			TestLinkedList::remove(&0, 1);
+
+			assert_eq!(
+				TestItem::get(&(0, None)),
+				Some(TestLinkedItem {
+					prev: Some(3),
+					next: Some(3),
+				})
+			);
+
+			assert_eq!(TestItem::get(&(0, Some(1))), None);
+
+			assert_eq!(TestItem::get(&(0, Some(2))), None);
+
+			assert_eq!(
+				TestItem::get(&(0, Some(3))),
+				Some(TestLinkedItem { prev: None, next: None })
+			);
+
+			TestLinkedList::remove(&0, 3);
+
+			assert_eq!(
+				TestItem::get(&(0, None)),
+				Some(TestLinkedItem { prev: None, next: None })
+			);
+
+			assert_eq!(TestItem::get(&(0, Some(1))), None);
+
+			assert_eq!(TestItem::get(&(0, Some(2))), None);
+
+			assert_eq!(TestItem::get(&(0, Some(2))), None);
+		});
+	}
+}