Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
parity
Mirrored projects
ink
Commits
03825afb
Unverified
Commit
03825afb
authored
Oct 03, 2019
by
Denis_P
🏑
Committed by
GitHub
Oct 03, 2019
Browse files
Merge branch 'master' into create_ci
parents
62ab7000
d92462b3
Pipeline
#53211
failed with stages
in 2 minutes and 33 seconds
Changes
7
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
core/src/storage/alloc/bump_alloc.rs
View file @
03825afb
...
...
@@ -28,7 +28,7 @@ use type_metadata::Metadata;
/// It is not designed to be used during contract execution and it
/// also cannot deallocate key allocated by it.
///
/// Users are recommended to use the [`
CellChunk
Alloc`](struct.
CellChunk
Alloc.html)
/// Users are recommended to use the [`
Dyn
Alloc`](struct.
Dyn
Alloc.html)
/// for dynamic storage allocation purposes instead.
#[cfg_attr(feature
=
"ink-generate-abi"
,
derive(Metadata))]
pub
struct
BumpAlloc
{
...
...
core/src/storage/alloc/cc_alloc.rs
deleted
100644 → 0
View file @
62ab7000
// Copyright 2018-2019 Parity Technologies (UK) Ltd.
// This file is part of ink!.
//
// ink! 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.
//
// ink! 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 ink!. If not, see <http://www.gnu.org/licenses/>.
use
super
::
*
;
use
crate
::
storage
::{
self
,
Flush
,
Key
,
};
#[cfg(feature
=
"ink-generate-abi"
)]
use
ink_abi
::{
HasLayout
,
LayoutField
,
LayoutStruct
,
StorageLayout
,
};
use
scale
::{
Decode
,
Encode
,
};
#[cfg(feature
=
"ink-generate-abi"
)]
use
type_metadata
::
Metadata
;
/// An allocator for the contract storage.
///
/// Specialized to efficiently allocate and deallocate cells and chunks.
///
/// # Note
///
/// This allocator allows for two types of allocations:
///
/// 1. Single cell allocation
/// 2. Cell chunk allocation (2^32 cells)
///
/// Allocating and deallocating are always O(1) operations.
#[derive(Debug,
Encode,
Decode)]
#[cfg_attr(feature
=
"ink-generate-abi"
,
derive(Metadata))]
pub
struct
CellChunkAlloc
{
/// Allocator stash for single cells.
cells
:
storage
::
Stash
<
()
>
,
/// Allocator stash for cell chunks.
chunks
:
storage
::
Stash
<
()
>
,
/// Cells key offset.
cells_off
:
Key
,
/// Chunks key offset.
chunks_off
:
Key
,
}
impl
AllocateUsing
for
CellChunkAlloc
{
/// Creates a new cell & chunks allocator using the given allocator.
///
/// The cell & chunks allocator is the default allocator for dynamic
/// storage allocations that may be required by some smart contracts
/// during smart contract execution.
///
/// # Note
///
/// At first it might seem strange to allocate one allocator with another.
/// Normally [`CellChunkAlloc`](struct.CellChunkAlloc.html) should be allocated
/// using a [`BumpAlloc`](struct.BumpAlloc.html).
/// The [`BumpAlloc`](struct.BumpAlloc.html) itself cannot be stored in the
/// contract storage and should also not be used for dynamic storage
/// allocations since it panics upon deallocation.
///
/// Store your only instance of the cell & chunks allocator on the storage
/// once upon deployment of your contract and reuse that instance for
/// all consecutive executions.
unsafe
fn
allocate_using
<
A
>
(
alloc
:
&
mut
A
)
->
Self
where
A
:
Allocate
,
{
Self
{
cells
:
AllocateUsing
::
allocate_using
(
alloc
),
chunks
:
AllocateUsing
::
allocate_using
(
alloc
),
cells_off
:
alloc
.alloc
(
u32
::
max_value
()
.into
()),
chunks_off
:
alloc
.alloc
(
u32
::
max_value
()
.into
()),
}
}
}
impl
Initialize
for
CellChunkAlloc
{
type
Args
=
();
fn
initialize
(
&
mut
self
,
_args
:
Self
::
Args
)
{
self
.cells
.initialize
(());
self
.chunks
.initialize
(());
}
}
impl
Flush
for
CellChunkAlloc
{
fn
flush
(
&
mut
self
)
{
self
.cells
.flush
();
self
.chunks
.flush
();
}
}
#[cfg(feature
=
"ink-generate-abi"
)]
impl
HasLayout
for
CellChunkAlloc
{
fn
layout
(
&
self
)
->
StorageLayout
{
LayoutStruct
::
new
(
Self
::
meta_type
(),
vec!
[
LayoutField
::
of
(
"cells"
,
&
self
.cells
),
LayoutField
::
of
(
"chunks"
,
&
self
.chunks
),
],
)
.into
()
}
}
impl
CellChunkAlloc
{
/// Returns the key to the first cell allocation.
///
/// # Note
///
/// This key is then used to determine the key for every
/// other cell allocation using its allocation index.
pub
(
crate
)
fn
cells_offset_key
(
&
self
)
->
Key
{
self
.cells_off
}
/// Returns the key to the first chunk allocation.
///
/// # Note
///
/// This key is then used to determine the key for every
/// other chunk allocation using its allocation index.
pub
(
crate
)
fn
chunks_offset_key
(
&
self
)
->
Key
{
self
.chunks_off
}
/// Allocates a new storage region that fits for a single cell.
fn
alloc_cell
(
&
mut
self
)
->
Key
{
let
index
=
self
.cells
.put
(());
self
.cell_index_to_key
(
index
)
}
/// Allocates a new storage region that fits for a whole chunk.
fn
alloc_chunk
(
&
mut
self
)
->
Key
{
let
index
=
self
.chunks
.put
(());
self
.chunk_index_to_key
(
index
)
}
/// Deallocates a storage region fit for a single cell.
fn
dealloc_cell
(
&
mut
self
,
key
:
Key
)
{
let
index
=
self
.key_to_cell_index
(
key
);
self
.cells
.take
(
index
)
.expect
(
"[ink_core::CellChunkAlloc::dealloc_cell] Error:
\
key was not allocated by the allocator"
,
)
}
/// Deallocates a storage region fit for a whole chunk.
fn
dealloc_chunk
(
&
mut
self
,
key
:
Key
)
{
let
index
=
self
.key_to_chunk_index
(
key
);
self
.chunks
.take
(
index
)
.expect
(
"[ink_core::CellChunkAlloc::dealloc_chunk] Error:
\
key was not allocated by the allocator"
,
)
}
/// Converts cell indices to keys.
///
/// The reverse of `key_to_cell_index`.
fn
cell_index_to_key
(
&
self
,
index
:
u32
)
->
Key
{
self
.cells_offset_key
()
+
index
}
/// Converts keys to cell indices.
///
/// The reverse of `cell_index_to_key`.
fn
key_to_cell_index
(
&
self
,
key
:
Key
)
->
u32
{
let
diff
=
key
-
self
.cells_offset_key
();
diff
.try_to_u32
()
.expect
(
"if allocated by this allocator the difference between
the given key and offset key must be less-than or equal
to u32::MAX."
,
)
}
/// Converts chunk indices to keys.
///
/// The reverse of `key_to_chunk_index`.
fn
chunk_index_to_key
(
&
self
,
index
:
u32
)
->
Key
{
let
chunk_offset
:
u64
=
(
1
<<
32
)
*
u64
::
from
(
index
);
self
.chunks_offset_key
()
+
chunk_offset
}
/// Converts keys to chunk indices.
///
/// The reverse of `chunk_index_to_key`.
fn
key_to_chunk_index
(
&
self
,
key
:
Key
)
->
u32
{
let
diff
=
key
-
self
.cells_offset_key
();
let
index
=
diff
.try_to_u64
()
.expect
(
"if allocated by this allocator the difference between
the given key and offset key must be less-than or equal
to u64::MAX."
,
);
(
index
>>
32
)
as
u32
}
}
impl
Allocate
for
CellChunkAlloc
{
/// Can only allocate sizes of up to `u32::MAX`.
fn
alloc
(
&
mut
self
,
size
:
u64
)
->
Key
{
assert!
(
size
<=
u64
::
from
(
u32
::
max_value
()));
debug_assert!
(
size
!=
0
);
if
size
==
1
{
self
.alloc_cell
()
}
else
{
self
.alloc_chunk
()
}
}
}
impl
Allocator
for
CellChunkAlloc
{
fn
dealloc
(
&
mut
self
,
key
:
Key
)
{
// This assumes that the given key was previously
// generated by the associated call to `Allocator::alloc`
// of this same allocator implementor.
assert!
(
key
>=
self
.cells_offset_key
());
// This condition requires cells offset key
// to be always smaller than chunks offset key.
//
// This must either be an invariant or we need
// another more safe condition in the future.
if
key
<
self
.chunks_offset_key
()
{
// The key was allocated as a cell
self
.dealloc_cell
(
key
)
}
else
{
// The key was allocated as a chunk
self
.dealloc_chunk
(
key
)
}
}
}
core/src/storage/alloc/mod.rs
View file @
03825afb
...
...
@@ -17,7 +17,6 @@
//! Facilities to allocate and deallocate contract storage dynamically.
mod
bump_alloc
;
mod
cc_alloc
;
mod
dyn_alloc
;
mod
traits
;
...
...
@@ -26,7 +25,6 @@ mod tests;
pub
use
self
::{
bump_alloc
::
BumpAlloc
,
cc_alloc
::
CellChunkAlloc
,
dyn_alloc
::
DynAlloc
,
traits
::{
Allocate
,
...
...
core/src/storage/alloc/tests.rs
View file @
03825afb
...
...
@@ -21,62 +21,6 @@ use crate::{
test_utils
::
run_test
,
};
#[test]
fn
cc_simple
()
{
run_test
(||
{
use
crate
::
storage
;
let
mut
alloc
=
unsafe
{
let
mut
fw_alloc
=
storage
::
alloc
::
BumpAlloc
::
from_raw_parts
(
Key
([
0x0
;
32
]));
let
mut
cc_alloc
=
storage
::
alloc
::
CellChunkAlloc
::
allocate_using
(
&
mut
fw_alloc
);
cc_alloc
.initialize
(());
cc_alloc
};
let
cells_entries
=
alloc
.cells_offset_key
();
let
chunks_entries
=
alloc
.chunks_offset_key
();
let
mut
cell_allocs
=
[
Key
([
0
;
32
]);
5
];
let
mut
chunk_allocs
=
[
Key
([
0
;
32
]);
5
];
// Cell allocations
for
i
in
0
..
5
{
cell_allocs
[
i
]
=
alloc
.alloc
(
1
);
assert_eq!
(
cell_allocs
[
i
],
cells_entries
+
(
i
as
u32
));
}
// Chunk allocations
let
alloc_sizes
=
&
[
10
,
u32
::
max_value
()
as
u64
,
1337
,
2
,
9999_9999
];
for
(
i
,
&
size
)
in
alloc_sizes
.into_iter
()
.enumerate
()
{
chunk_allocs
[
i
]
=
alloc
.alloc
(
size
);
assert_eq!
(
chunk_allocs
[
i
],
chunks_entries
+
((
1
<<
32
)
*
(
i
as
u64
)));
}
// Deallocate first cell again
alloc
.dealloc
(
cell_allocs
[
0
]);
// Now the next cell allocation will take the first allocation cell again
assert_eq!
(
alloc
.alloc
(
1
),
cell_allocs
[
0
]);
// Deallocate 2nd and 4th allocations in reverse order
alloc
.dealloc
(
cell_allocs
[
3
]);
alloc
.dealloc
(
cell_allocs
[
1
]);
assert_eq!
(
alloc
.alloc
(
1
),
cell_allocs
[
1
]);
assert_eq!
(
alloc
.alloc
(
1
),
cell_allocs
[
3
]);
// Deallocate first chunk again
alloc
.dealloc
(
chunk_allocs
[
0
]);
// Now the next chunk allocation will take the first allocation cell again
assert_eq!
(
alloc
.alloc
(
u32
::
max_value
()
as
u64
),
chunk_allocs
[
0
]);
// Deallocate 2nd and 4th allocations in reverse order
alloc
.dealloc
(
chunk_allocs
[
3
]);
alloc
.dealloc
(
chunk_allocs
[
1
]);
assert_eq!
(
alloc
.alloc
(
u32
::
max_value
()
as
u64
),
chunk_allocs
[
1
]);
assert_eq!
(
alloc
.alloc
(
u32
::
max_value
()
as
u64
),
chunk_allocs
[
3
]);
})
}
#[test]
fn
dyn_simple
()
{
run_test
(||
{
...
...
model/src/contract.rs
View file @
03825afb
...
...
@@ -253,7 +253,7 @@ where
{
/// Creates an instance of the contract declaration.
///
/// This assocates the state with the contract storage
/// This assoc
i
ates the state with the contract storage
/// and defines its layout.
pub
fn
instantiate
(
self
)
->
ContractInstance
<
State
,
Env
,
DeployArgs
,
HandlerChain
>
{
use
ink_core
::
storage
::{
...
...
@@ -263,7 +263,7 @@ where
},
Key
,
};
let
env
:
ExecutionEnv
<
State
,
Env
>
=
unsafe
{
let
env
=
unsafe
{
// Note that it is totally fine here to start with a key
// offset of `0x0` as long as we only consider having one
// contract instance per execution. Otherwise their
...
...
model/src/exec_env.rs
View file @
03825afb
...
...
@@ -25,7 +25,7 @@ use ink_core::{
storage
::
alloc
::{
Allocate
,
AllocateUsing
,
CellChunk
Alloc
,
Dyn
Alloc
,
Initialize
,
},
};
...
...
@@ -110,7 +110,7 @@ impl<State, Env> ExecutionEnv<State, Env> {
/// allocations and deallocations.
pub
struct
EnvHandler
<
T
>
{
/// The dynamic allocator.
pub
dyn_alloc
:
CellChunk
Alloc
,
pub
dyn_alloc
:
Dyn
Alloc
,
env_marker
:
PhantomData
<
T
>
,
}
...
...
model/tests/incrementer.rs
View file @
03825afb
...
...
@@ -68,17 +68,3 @@ fn inc_and_read() {
contract
.call
::
<
Inc
>
(
41
);
assert_eq!
(
contract
.call
::
<
Get
>
(()),
42_u32
);
}
#[test]
#[should_panic]
fn
read_without_deploy
()
{
let
mut
contract
=
instantiate
();
let
_res
=
contract
.call
::
<
Get
>
(());
}
#[test]
#[should_panic]
fn
write_without_deploy
()
{
let
mut
contract
=
instantiate
();
contract
.call
::
<
Inc
>
(
100
);
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment