1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079
use crate::{
cell::UnsafeCell, marker::PhantomData, num::NonZeroU32, Cursor, HasStateApi, Serial, Vec,
};
#[derive(Debug)]
/// A high-level map based on the low-level key-value store, which is the
/// interface provided by the chain.
///
/// In most situations, this collection should be preferred over
/// [`BTreeMap`][btm] and [`HashMap`][hm] since it will be more efficient to
/// lookup and update since costs to lookup and update will grow very slowly
/// with the size of the collection. In contrast, using [`BTreeMap`][btm] and
/// [`HashMap`][hm] almost always entails their serialization, which is linear
/// in the size of the collection.
///
/// The cost of updates to the map are dependent on the length of `K` (in bytes)
/// and the size of the data stored (`V`). Short keys are therefore ideal.
///
/// New maps can be constructed using the
/// [`new_map`][StateBuilder::new_map] method on the [`StateBuilder`].
///
///
/// ```
/// # use concordium_std::*;
/// # use concordium_std::test_infrastructure::*;
/// # let mut state_builder = TestStateBuilder::new();
/// /// In an init method:
/// let mut map1 = state_builder.new_map();
/// # map1.insert(0u8, 1u8); // Specifies type of map.
///
/// # let mut host = TestHost::new((), state_builder);
/// /// In a receive method:
/// let mut map2 = host.state_builder().new_map();
/// # map2.insert(0u16, 1u16);
/// ```
///
/// ## Type parameters
///
/// The map `StateMap<K, V, S>` is parametrized by the type of _keys_ `K`, the
/// type of _values_ `V` and the type of the low-level state `S`. In line with
/// other Rust collections, e.g., [`BTreeMap`][btm] and [`HashMap`][hm]
/// constructing the statemap via [`new_map`](StateBuilder::new_map) does not
/// require anything specific from `K` and `V`. However most operations do
/// require that `K` is serializable and `V` can be stored and loaded in the
/// context of the low-level state `S`.
///
/// This concretely means that `K` must implement
/// [`Serialize`](crate::Serialize) and `V` has to implement
/// [`Serial`](crate::Serial) and
/// [`DeserialWithState<S>`](crate::DeserialWithState). In practice, this means
/// that keys must be _flat_, meaning that it cannot have any references to the
/// low-level state. This is almost all types, except [`StateBox`], [`StateMap`]
/// and [`StateSet`] and types containing these.
///
/// However values may contain references to the low-level state, in particular
/// maps may be nested.
///
/// ### Low-level state `S`
///
/// The type parameter `S` is extra compared to usual Rust collections. As
/// mentioned above it specifies the [low-level state
/// implementation](crate::HasStateApi). This library provides two such
/// implementations. The "external" one, which is the implementation supported
/// by external host functions provided by the chain, and a
/// [test](crate::test_infrastructure::TestStateApi) one. The latter one is
/// useful for testing since it provides an implementation that is easier to
/// construct, execute, and inspect during unit testing.
///
/// In user code this type parameter should generally be treated as boilerplate,
/// and contract entrypoints should always be stated in terms of a generic type
/// `S` that implements [HasStateApi](crate::HasStateApi)
///
/// #### Example
/// ```rust
/// # use concordium_std::*;
/// #[derive(Serial, DeserialWithState)]
/// #[concordium(state_parameter = "S")]
/// struct MyState<S: HasStateApi> {
/// inner: StateMap<u64, u64, S>,
/// }
/// #[init(contract = "mycontract")]
/// fn contract_init<S: HasStateApi>(
/// _ctx: &impl HasInitContext,
/// state_builder: &mut StateBuilder<S>,
/// ) -> InitResult<MyState<S>> {
/// Ok(MyState {
/// inner: state_builder.new_map(),
/// })
/// }
///
/// #[receive(contract = "mycontract", name = "receive", return_value = "Option<u64>")]
/// fn contract_receive<S: HasStateApi>(
/// _ctx: &impl HasReceiveContext,
/// host: &impl HasHost<MyState<S>, StateApiType = S>, // the same low-level state must be propagated throughout
/// ) -> ReceiveResult<Option<u64>> {
/// let state = host.state();
/// Ok(state.inner.get(&0).map(|v| *v))
/// }
/// ```
///
/// ## **Caution**
///
/// `StateMap`s must be explicitly deleted when they are no longer needed,
/// otherwise they will remain in the contract's state, albeit unreachable.
///
/// ```no_run
/// # use concordium_std::*;
/// struct MyState<S: HasStateApi> {
/// inner: StateMap<u64, u64, S>,
/// }
/// fn incorrect_replace<S: HasStateApi>(
/// state_builder: &mut StateBuilder<S>,
/// state: &mut MyState<S>,
/// ) {
/// // The following is incorrect. The old value of `inner` is not properly deleted.
/// // from the state.
/// state.inner = state_builder.new_map(); // ⚠️
/// }
/// ```
/// Instead, either the map should be [cleared](StateMap::clear) or
/// explicitly deleted.
///
/// ```no_run
/// # use concordium_std::*;
/// # struct MyState<S: HasStateApi> {
/// # inner: StateMap<u64, u64, S>
/// # }
/// fn correct_replace<S: HasStateApi>(
/// state_builder: &mut StateBuilder<S>,
/// state: &mut MyState<S>,
/// ) {
/// state.inner.clear_flat();
/// }
/// ```
/// Or alternatively
/// ```no_run
/// # use concordium_std::*;
/// # struct MyState<S: HasStateApi> {
/// # inner: StateMap<u64, u64, S>
/// # }
/// fn correct_replace<S: HasStateApi>(
/// state_builder: &mut StateBuilder<S>,
/// state: &mut MyState<S>,
/// ) {
/// let old_map = mem::replace(&mut state.inner, state_builder.new_map());
/// old_map.delete()
/// }
/// ```
///
/// [hm]: crate::collections::HashMap
/// [btm]: crate::collections::BTreeMap
pub struct StateMap<K, V, S> {
pub(crate) _marker_key: PhantomData<K>,
pub(crate) _marker_value: PhantomData<V>,
pub(crate) prefix: StateItemPrefix,
pub(crate) state_api: S,
}
#[derive(Debug)]
/// An iterator over the entries of a [`StateMap`].
///
/// Ordered by `K` serialized to bytes.
///
/// This `struct` is created by the [`iter`][StateMap::iter] method on
/// [`StateMap`]. See its documentation for more.
pub struct StateMapIter<'a, K, V, S: HasStateApi> {
pub(crate) state_iter: Option<S::IterType>,
pub(crate) state_api: S,
pub(crate) _lifetime_marker: PhantomData<&'a (K, V)>,
}
#[derive(Debug)]
/// A mutable iterator over the entries of a [`StateMap`].
///
/// Ordered lexicographically by `K` via its serialization.
///
/// This `struct` is created by the [`iter_mut`][StateMap::iter_mut] method on
/// [`StateMap`]. See its documentation for more.
pub struct StateMapIterMut<'a, K, V, S: HasStateApi> {
pub(crate) state_iter: Option<S::IterType>,
pub(crate) state_api: S,
pub(crate) _lifetime_marker: PhantomData<&'a mut (K, V)>,
}
#[derive(Debug)]
/// A high-level set of _flat_ values based on the low-level key-value store,
/// which is the interface provided by the chain.
///
/// In most situations, this collection should be preferred over
/// [`BTreeSet`][bts] and [`HashSet`][hs] since it will be more efficient to
/// lookup and update since costs to lookup and update will grow very slowly
/// with the size of the collection. In contrast, using [`BTreeSet`][bts] and
/// [`HashSet`][hs] almost always entails their serialization, which is linear
/// in the size of the collection.
///
/// The cost of updates to the set are dependent on the serialized size of the
/// value `T`.
///
/// New sets can be constructed using the
/// [`new_set`][StateBuilder::new_set] method on the [`StateBuilder`].
///
/// ## Type parameters
///
/// The set `StateSet<T, S>` is parametrized by the type of _values_ `T`, and
/// the type of the low-level state `S`. In line with other Rust collections,
/// e.g., [`BTreeSet`][bts] and [`HashSet`][hs] constructing the stateset via
/// [`new_set`](StateBuilder::new_set) does not require anything specific from
/// `T`. However most operations do require that `T` implements
/// [`Serialize`](crate::Serialize).
///
/// Since `StateSet<T, S>` itself **does not** implement
/// [`Serialize`](crate::Serialize) **sets cannot be nested**. If this is really
/// required then a custom solution should be devised using the operations on
/// `S` (see [HasStateApi](crate::HasStateApi)).
///
/// ### Low-level state `S`
///
/// The type parameter `S` is extra compared to usual Rust collections. As
/// mentioned above it specifies the [low-level state
/// implementation](crate::HasStateApi). This library provides two such
/// implementations. The "external" one, which is the implementation supported
/// by external host functions provided by the chain, and a
/// [test](crate::test_infrastructure::TestStateApi) one. The latter one is
/// useful for testing since it provides an implementation that is easier to
/// construct, execute, and inspect during unit testing.
///
/// In user code this type parameter should generally be treated as boilerplate,
/// and contract entrypoints should always be stated in terms of a generic type
/// `S` that implements [HasStateApi](crate::HasStateApi)
///
/// #### Example
/// ```rust
/// # use concordium_std::*;
/// #[derive(Serial, DeserialWithState)]
/// #[concordium(state_parameter = "S")]
/// struct MyState<S: HasStateApi> {
/// inner: StateSet<u64, S>,
/// }
/// #[init(contract = "mycontract")]
/// fn contract_init<S: HasStateApi>(
/// _ctx: &impl HasInitContext,
/// state_builder: &mut StateBuilder<S>,
/// ) -> InitResult<MyState<S>> {
/// Ok(MyState {
/// inner: state_builder.new_set(),
/// })
/// }
///
/// #[receive(contract = "mycontract", name = "receive", return_value = "bool")]
/// fn contract_receive<S: HasStateApi>(
/// _ctx: &impl HasReceiveContext,
/// host: &impl HasHost<MyState<S>, StateApiType = S>, // the same low-level state must be propagated throughout
/// ) -> ReceiveResult<bool> {
/// let state = host.state();
/// Ok(state.inner.contains(&0))
/// }
/// ```
///
/// ## **Caution**
///
/// `StateSet`s must be explicitly deleted when they are no longer needed,
/// otherwise they will remain in the contract's state, albeit unreachable.
///
/// ```no_run
/// # use concordium_std::*;
/// struct MyState<S: HasStateApi> {
/// inner: StateSet<u64, S>,
/// }
/// fn incorrect_replace<S: HasStateApi>(
/// state_builder: &mut StateBuilder<S>,
/// state: &mut MyState<S>,
/// ) {
/// // The following is incorrect. The old value of `inner` is not properly deleted.
/// // from the state.
/// state.inner = state_builder.new_set(); // ⚠️
/// }
/// ```
/// Instead, either the set should be [cleared](StateSet::clear) or
/// explicitly deleted.
///
/// ```no_run
/// # use concordium_std::*;
/// # struct MyState<S: HasStateApi> {
/// # inner: StateSet<u64, S>
/// # }
/// fn correct_replace<S: HasStateApi>(
/// state_builder: &mut StateBuilder<S>,
/// state: &mut MyState<S>,
/// ) {
/// state.inner.clear();
/// }
/// ```
/// Or alternatively
/// ```no_run
/// # use concordium_std::*;
/// # struct MyState<S: HasStateApi> {
/// # inner: StateSet<u64, S>
/// # }
/// fn correct_replace<S: HasStateApi>(
/// state_builder: &mut StateBuilder<S>,
/// state: &mut MyState<S>,
/// ) {
/// let old_set = mem::replace(&mut state.inner, state_builder.new_set());
/// old_set.delete()
/// }
/// ```
///
/// [hs]: crate::collections::HashSet
/// [bts]: crate::collections::BTreeSet
pub struct StateSet<T, S> {
pub(crate) _marker: PhantomData<T>,
pub(crate) prefix: StateItemPrefix,
pub(crate) state_api: S,
}
/// An iterator over the entries of a [`StateMap`].
///
/// Ordered by `T` serialized to bytes.
///
/// This `struct` is created by the [`iter`][StateSet::iter] method on
/// [`StateSet`]. See its documentation for more.
pub struct StateSetIter<'a, T, S: HasStateApi> {
pub(crate) state_iter: Option<S::IterType>,
pub(crate) state_api: S,
pub(crate) _marker_lifetime: PhantomData<&'a T>,
}
#[derive(Debug)]
/// A pointer type for data in the state.
///
/// The actual data is lazily loaded and thereafter cached in memory.
///
/// Due to its laziness, a [`StateBox`] can be used to defer loading of data in
/// your state. This is useful when part of your state isn't used in every
/// receive method.
///
/// The type parameter `T` is the type stored in the box. The type parameter `S`
/// is the state.
pub struct StateBox<T: Serial, S: HasStateApi> {
pub(crate) state_api: S,
pub(crate) inner: UnsafeCell<StateBoxInner<T, S>>,
}
pub(crate) enum StateBoxInner<T, S: HasStateApi> {
/// Value is loaded in memory, and we have a backing entry.
Loaded {
entry: S::EntryType,
modified: bool,
value: T,
},
/// We only have the memory location at which the value is stored.
Reference {
prefix: StateItemPrefix,
},
}
#[derive(Debug)]
/// The [`StateRef`] behaves akin the type `&'a V`, except that it is not
/// copyable. It should be used as [MutexGuard](std::sync::MutexGuard) or
/// similar types which guard access to a resource.
///
/// The type implements [`Deref`][crate::ops::Deref] to `V`, and that is the
/// intended, and only, way to use it.
pub struct StateRef<'a, V> {
pub(crate) value: V,
pub(crate) _marker_lifetime: PhantomData<&'a V>,
}
impl<'a, V> StateRef<'a, V> {
#[inline(always)]
pub(crate) fn new(value: V) -> Self {
Self {
value,
_marker_lifetime: PhantomData,
}
}
}
impl<'a, V> crate::ops::Deref for StateRef<'a, V> {
type Target = V;
#[inline(always)]
fn deref(&self) -> &Self::Target { &self.value }
}
#[derive(Debug)]
/// The [`StateRefMut<_, V, _>`] behaves like `&mut V`, by analogy with other
/// standard library RAII guards like [`RefMut`](std::cell::RefMut).
/// The type implements [`DerefMut`](crate::ops::DerefMut) which allows the
/// value to be mutated. Additionally, the [`Drop`](Drop) implementation ensures
/// that the value is properly stored in the contract state maintained by the
/// node.
pub struct StateRefMut<'a, V: Serial, S: HasStateApi> {
pub(crate) entry: UnsafeCell<S::EntryType>,
pub(crate) state_api: S,
pub(crate) lazy_value: UnsafeCell<Option<V>>,
pub(crate) _marker_lifetime: PhantomData<&'a mut V>,
}
impl<'a, V: Serial, S: HasStateApi> StateRefMut<'a, V, S> {
#[inline(always)]
pub(crate) fn new(entry: S::EntryType, state_api: S) -> Self {
Self {
entry: UnsafeCell::new(entry),
state_api,
lazy_value: UnsafeCell::new(None),
_marker_lifetime: PhantomData,
}
}
}
#[derive(Debug)]
#[repr(transparent)]
/// An iterator over a part of the state. Its implementation is supported by
/// host calls.
#[doc(hidden)]
pub struct ExternStateIter {
pub(crate) iterator_id: StateIteratorId,
}
pub(crate) type StateEntryId = u64;
pub(crate) type StateIteratorId = u64;
pub(crate) type StateItemPrefix = [u8; 8];
/// Type of keys that index into the contract state.
pub type Key = Vec<u8>;
/// Represents the data in a node in the state trie.
pub struct StateEntry {
pub(crate) state_entry_id: StateEntryId,
pub(crate) key: Key,
pub(crate) current_position: u32,
}
/// A view into a vacant entry in a [`HasStateApi`][`crate::HasStateApi`] type.
/// It is part of the [`EntryRaw`] enum.
///
/// Differs from [`VacantEntry`] in that this has access to the raw bytes stored
/// in the state via a [`HasStateEntry`][crate::HasStateEntry] type.
pub struct VacantEntryRaw<S> {
pub(crate) key: Key,
pub(crate) state_api: S,
}
#[repr(transparent)]
/// A view into an occupied entry in a [`HasStateApi`][`crate::HasStateApi`]
/// type. It is part of the [`EntryRaw`] enum.
///
/// Differs from [`OccupiedEntry`] in that this has access to the raw bytes
/// stored in the state via a [`HasStateEntry`][crate::HasStateEntry] type.
pub struct OccupiedEntryRaw<StateApi: HasStateApi> {
pub(crate) state_entry: StateApi::EntryType,
}
/// A view into a single entry in a [`HasStateApi`][`crate::HasStateApi`] type,
/// which may either be vacant or occupied.
///
/// This `enum` is constructed from the [`entry`][crate::HasStateApi::entry]
/// method on a [`HasStateApi`][crate::HasStateApi] type.
pub enum EntryRaw<StateApi: HasStateApi> {
Vacant(VacantEntryRaw<StateApi>),
Occupied(OccupiedEntryRaw<StateApi>),
}
/// A view into a vacant entry in a [`StateMap`]. It is
/// part of the [`Entry`] enum.
///
/// Differs from [`VacantEntryRaw`] in that this automatically handles
/// serialization.
pub struct VacantEntry<'a, K, V, S> {
pub(crate) key: K,
pub(crate) key_bytes: Vec<u8>,
pub(crate) state_api: S,
pub(crate) _lifetime_marker: PhantomData<&'a mut (K, V)>,
}
/// A view into an occupied entry in a [`StateMap`]. It can be obtained via the
/// [`StateMap::entry`] method. This allows looking up or modifying the value at
/// a give key in-place.
///
/// The type implements [`DerefMut`](crate::ops::DerefMut) which allows the
/// value to be mutated. The [`Drop`](Drop) implementation ensures
/// that the value is properly stored in the contract state maintained by the
/// node.
///
/// This differs from [`OccupiedEntryRaw`] in that this automatically handles
/// serialization and provides convenience methods for modifying the value via
/// the [`DerefMut`](crate::ops::DerefMut) implementation.
pub struct OccupiedEntry<'a, K, V: Serial, S: HasStateApi> {
pub(crate) key: K,
pub(crate) value: V,
/// Indicates whether the value should be stored by the drop implementation.
/// This is set when deref_mut method is called only, since that is when we
/// **might** implicitly mutate the value.
pub(crate) modified: bool,
pub(crate) state_entry: S::EntryType,
pub(crate) _lifetime_marker: PhantomData<&'a mut (K, V)>,
}
impl<'a, K, V: Serial, S: HasStateApi> crate::ops::Deref for OccupiedEntry<'a, K, V, S> {
type Target = V;
#[inline(always)]
fn deref(&self) -> &Self::Target { &self.value }
}
impl<'a, K, V: Serial, S: HasStateApi> crate::ops::DerefMut for OccupiedEntry<'a, K, V, S> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
self.modified = true;
&mut self.value
}
}
impl<'a, K, V: Serial, S: HasStateApi> Drop for OccupiedEntry<'a, K, V, S> {
#[inline(always)]
fn drop(&mut self) {
if self.modified {
self.store_value()
}
}
}
/// A view into a single entry in a [`StateMap`], which
/// may either be vacant or occupied.
///
/// This `enum` is constructed from the [`entry`][StateMap::entry] method
/// on a [`StateMap`] type.
pub enum Entry<'a, K, V: Serial, S: HasStateApi> {
Vacant(VacantEntry<'a, K, V, S>),
Occupied(OccupiedEntry<'a, K, V, S>),
}
/// Zero-sized placeholder for the parameter data, only used internally by
/// [ExternParameter].
#[doc(hidden)]
pub(crate) struct ExternParameterDataPlaceholder {}
/// A type representing the parameter to init and receive methods.
/// Its trait implementations are backed by host functions.
#[doc(hidden)]
pub struct ExternParameter {
pub(crate) cursor: Cursor<ExternParameterDataPlaceholder>,
}
/// A type representing the return value of contract invocation.
/// A contract invocation **may** return a value. It is returned in the
/// following cases
/// - an entrypoint of a V1 contract was invoked and the invocation succeeded
/// - an entrypoint of a V1 contract was invoked and the invocation failed due
/// to a [CallContractError::LogicReject]
///
/// In all other cases there is no response.
///
/// This type is designed to be used via its [Read](crate::Read) and
/// [HasCallResponse](crate::HasCallResponse) traits.
#[derive(Debug)]
#[doc(hidden)]
pub struct ExternCallResponse {
/// The index of the call response.
pub(crate) i: NonZeroU32,
pub(crate) current_position: u32,
}
impl ExternCallResponse {
#[inline(always)]
/// Construct a new call response with the given index,
/// and starting position set to 0.
pub(crate) fn new(i: NonZeroU32) -> Self {
Self {
i,
current_position: 0,
}
}
}
/// A type representing the return value of contract init or receive method.
/// The intention is that this type is manipulated using methods of the
/// [Write](crate::Write) trait. In particular it can be used as a sink to
/// serialize values into.
pub struct ExternReturnValue {
pub(crate) current_position: u32,
}
#[repr(i32)]
#[derive(Debug, Clone, Copy)]
/// Errors that may occur when invoking a contract entrypoint.
pub enum CallContractError<ReturnValueType> {
/// Amount that was to be transferred is not available to the sender.
AmountTooLarge,
/// Owner account of the smart contract that is being invoked does not
/// exist. This variant should in principle not happen, but is here for
/// completeness.
MissingAccount,
/// Contract that is to be invoked does not exist.
MissingContract,
/// The contract to be invoked exists, but the entrypoint that was named
/// does not.
MissingEntrypoint,
/// Sending a message to the V0 contract failed.
MessageFailed,
/// Contract that was called rejected with the given reason.
LogicReject {
reason: i32,
return_value: ReturnValueType,
},
/// Execution of a contract call triggered a runtime error.
Trap,
}
#[repr(i32)]
#[derive(Debug, Clone)]
/// Errors that may occur when transferring CCD to an account.
pub enum TransferError {
/// Amount that was to be transferred is not available to the sender.
AmountTooLarge,
/// Account that is to be transferred to does not exist.
MissingAccount,
}
/// A wrapper around [Result] that fixes the error variant to
/// [CallContractError], and the result to `(bool, Option<A>)`.
/// If the result is `Ok` then the boolean indicates whether the state was
/// modified or not, and the second item is the actual return value, which is
/// present (i.e., [`Some`]) if and only if a `V1` contract was invoked.
pub type CallContractResult<A> = Result<(bool, Option<A>), CallContractError<A>>;
/// A wrapper around [Result] that fixes the error variant to
/// [CallContractError], and the result to [`Option<A>`](Option)
/// If the result is `Ok` then the value is [`None`] if a `V0` contract was
/// invoked, and a return value returned by a `V1` contract otherwise.
pub type ReadOnlyCallContractResult<A> = Result<Option<A>, CallContractError<A>>;
/// A wrapper around [Result] that fixes the error variant to [TransferError]
/// and result to [()](https://doc.rust-lang.org/std/primitive.unit.html).
pub type TransferResult = Result<(), TransferError>;
/// A type representing the attributes, lazily acquired from the host.
#[derive(Clone, Copy, Default)]
pub struct AttributesCursor {
/// Current position of the cursor, starting from 0.
/// Note that this is only for the variable attributes.
/// `created_at` and `valid_to` will require.
pub(crate) current_position: u32,
/// The number of remaining items in the policy.
pub(crate) remaining_items: u16,
/// The total number of items. Used for creating new attribute cursors.
pub(crate) total_items: u16,
}
/// An iterator over the attributes of a policy.
/// The iterator returns pairs of [`AttributeTag`] and [`AttributeValue`].
#[repr(transparent)]
pub struct PolicyAttributesIter {
pub(crate) cursor: AttributesCursor,
}
/// A type representing the logger.
#[derive(Default)]
pub struct Logger {
pub(crate) _private: (),
}
/// Errors that can occur during logging.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(u8)]
pub enum LogError {
/// The log is full.
Full,
/// The message to log was malformed (e.g., too long)
Malformed,
}
/// Error triggered when a non-zero amount of CCD is sent to a contract
/// init or receive function that is not marked as `payable`.
#[derive(Clone, Copy, Debug)]
pub struct NotPayableError;
/// An error message, signalling rejection of a smart contract invocation.
/// The client will see the error code as a reject reason; if a schema is
/// provided, the error message corresponding to the error code will be
/// displayed. The valid range for an error code is from i32::MIN to -1.
/// A return value can also be provided.
#[derive(Eq, PartialEq, Debug)]
pub struct Reject {
pub error_code: crate::num::NonZeroI32,
pub return_value: Option<Vec<u8>>,
}
impl From<crate::num::NonZeroI32> for Reject {
#[inline(always)]
fn from(error_code: crate::num::NonZeroI32) -> Self {
Self {
error_code,
return_value: None,
}
}
}
/// Default error is i32::MIN.
impl Default for Reject {
#[inline(always)]
fn default() -> Self {
Self {
error_code: unsafe { crate::num::NonZeroI32::new_unchecked(i32::MIN) },
return_value: None,
}
}
}
impl Reject {
/// This returns `None` for all values >= 0 and `Some` otherwise.
pub fn new(x: i32) -> Option<Self> {
if x < 0 {
let error_code = unsafe { crate::num::NonZeroI32::new_unchecked(x) };
Some(Reject {
error_code,
return_value: None,
})
} else {
None
}
}
}
// Macros for failing a contract function
/// The `bail` macro can be used for cleaner error handling. If the function has
/// result type `Result` invoking `bail` will terminate execution early with an
/// error.
/// If an argument is supplied, this will be used as the error, otherwise it
/// requires the type `E` in `Result<_, E>` to implement the `Default` trait.
#[macro_export]
macro_rules! bail {
() => {{
return Err(Default::default());
}};
($arg:expr) => {{
// format_err!-like formatting
// logs are only retained in case of rejection when testing.
return Err($arg);
}};
}
/// The `ensure` macro can be used for cleaner error handling. It is analogous
/// to `assert`, but instead of panicking it uses `bail` to terminate execution
/// of the function early.
#[macro_export]
macro_rules! ensure {
($p:expr) => {
if !$p {
$crate::bail!();
}
};
($p:expr, $arg:expr) => {{
if !$p {
$crate::bail!($arg);
}
}};
}
/// ## Variants of `ensure` for ease of use in certain contexts.
/// Ensure the first two arguments are equal, using `bail` otherwise.
#[macro_export]
macro_rules! ensure_eq {
($l:expr, $r:expr) => {
$crate::ensure!($l == $r)
};
($l:expr, $r:expr, $arg:expr) => {
$crate::ensure!($l == $r, $arg)
};
}
#[macro_export]
/// Ensure the first two arguments are __not__ equal, using `bail` otherwise.
macro_rules! ensure_ne {
($l:expr, $r:expr) => {
$crate::ensure!($l != $r)
};
($l:expr, $r:expr, $arg:expr) => {
$crate::ensure!($l != $r, $arg)
};
}
// Macros for failing a test
/// The `fail` macro is used for testing as a substitute for the panic macro.
/// It reports back error information to the host.
/// Used only in testing.
#[cfg(feature = "std")]
#[macro_export]
macro_rules! fail {
() => {
{
$crate::test_infrastructure::report_error("", file!(), line!(), column!());
panic!()
}
};
($($arg:tt),+) => {
{
let msg = format!($($arg),+);
$crate::test_infrastructure::report_error(&msg, file!(), line!(), column!());
panic!("{}", msg)
}
};
}
/// The `fail` macro is used for testing as a substitute for the panic macro.
/// It reports back error information to the host.
/// Used only in testing.
#[cfg(not(feature = "std"))]
#[macro_export]
macro_rules! fail {
() => {
{
$crate::test_infrastructure::report_error("", file!(), line!(), column!());
panic!()
}
};
($($arg:tt),+) => {
{
let msg = &$crate::alloc::format!($($arg),+);
$crate::test_infrastructure::report_error(&msg, file!(), line!(), column!());
panic!("{}", msg)
}
};
}
/// The `claim` macro is used for testing as a substitute for the assert macro.
/// It checks the condition and if false it reports back an error.
/// Used only in testing.
#[macro_export]
macro_rules! claim {
($cond:expr) => {
if !$cond {
$crate::fail!()
}
};
($cond:expr,) => {
if !$cond {
$crate::fail!()
}
};
($cond:expr, $($arg:tt),+) => {
if !$cond {
$crate::fail!($($arg),+)
}
};
}
/// Ensure the first two arguments are equal, just like `assert_eq!`, otherwise
/// reports an error. Used only in testing.
#[macro_export]
macro_rules! claim_eq {
($left:expr, $right:expr $(,)?) => {
// Use match to ensure that the values are only evaluated once,
// and to ensure that type inference works correctly when printing.
match (&$left, &$right) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
$crate::fail!("left and right are not equal\nleft: {:?}\nright: {:?}\n", left_val, right_val);
}
}
}
};
($left:expr, $right:expr, $($arg:tt),+) => {
$crate::claim!($left == $right, $($arg),+)
};
}
/// Ensure the first two arguments are *not* equal, just like `assert_ne!`,
/// otherwise reports an error.
/// Used only in testing.
#[macro_export]
macro_rules! claim_ne {
($left:expr, $right:expr $(,)?) => {
// Use match to ensure that the values are only evaluated once,
// and to ensure that type inference works correctly when printing.
match (&$left, &$right) {
(left_val, right_val) => {
if *left_val == *right_val {
$crate::fail!("left and right are equal\nleft: {:?}\nright: {:?}\n", left_val, right_val);
}
}
}
};
($left:expr, $right:expr, $($arg:tt),+) => {
$crate::claim!($left != $right, $($arg),+)
};
}
/// The expected return type of the receive method of a smart contract.
///
/// Optionally, to define a custom type for error instead of using
/// Reject, allowing to track the reason for rejection, *but only in unit
/// tests*.
///
/// See also the documentation for [bail!](macro.bail.html) for how to use
/// custom error types.
///
/// # Example
/// Defining a custom error type that implements [`Reject`] and [`Serial`].
/// ```no_run
/// # use concordium_std::*;
/// #[derive(Serial, Reject)]
/// enum MyCustomError {
/// SomeError,
/// }
///
/// #[receive(contract = "mycontract", name = "receive")]
/// fn contract_receive<S: HasStateApi>(
/// _ctx: &impl HasReceiveContext,
/// _host: &impl HasHost<(), StateApiType = S>,
/// ) -> Result<(), MyCustomError> {
/// Err(MyCustomError::SomeError)
/// }
/// ```
pub type ReceiveResult<A> = Result<A, Reject>;
/// The expected return type of the init method of the smart contract,
/// parametrized by the state type of the smart contract.
///
/// Optionally, to define a custom type for error instead of using Reject,
/// allowing the track the reason for rejection, *but only in unit tests*.
///
/// See also the documentation for [bail!](macro.bail.html) for how to use
/// custom error types.
///
/// # Example
/// Defining a custom error type that implements [`Reject`] and [`Serial`].
/// ```no_run
/// # use concordium_std::*;
/// #[derive(Serial, Reject)]
/// enum MyCustomError {
/// SomeError,
/// }
///
/// #[init(contract = "mycontract")]
/// fn contract_init<S: HasStateApi>(
/// _ctx: &impl HasInitContext,
/// _state_builder: &mut StateBuilder<S>,
/// ) -> Result<(), MyCustomError> {
/// Err(MyCustomError::SomeError)
/// }
/// ```
pub type InitResult<S> = Result<S, Reject>;
/// Operations backed by host functions for the high-level interface.
#[doc(hidden)]
pub struct ExternHost<State> {
pub state: State,
pub state_builder: StateBuilder<ExternStateApi>,
}
#[derive(Default)]
/// An state builder that allows the creation of [`StateMap`], [`StateSet`], and
/// [`StateBox`]. It is parametrized by a parameter `S` that is assumed to
/// implement [`HasStateApi`].
///
/// The state_builder is designed to provide an abstraction over the contract
/// state, abstracting over the exact **keys** (keys in the sense of key-value
/// store, which is the low-level semantics of contract state) that are used
/// when storing specific values.
pub struct StateBuilder<S> {
pub(crate) state_api: S,
}
impl<S> StateBuilder<S> {
#[doc(hidden)]
pub fn into_inner(self) -> S { self.state_api }
}
/// A struct for which HasCryptoPrimitives is implemented via the crypto host
/// functions.
#[doc(hidden)]
pub struct ExternCryptoPrimitives;
/// Public key for Ed25519. Must be 32 bytes long.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
#[repr(transparent)]
pub struct PublicKeyEd25519(pub [u8; 32]);
/// Public key for ECDSA over Secp256k1. Must be 33 bytes long.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
#[repr(transparent)]
pub struct PublicKeyEcdsaSecp256k1(pub [u8; 33]);
/// Signature for a Ed25519 message. Must be 64 bytes long.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
#[repr(transparent)]
pub struct SignatureEd25519(pub [u8; 64]);
/// Signature for a ECDSA (over Secp256k1) message. Must be 64 bytes longs
/// (serialized in compressed format).
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
#[repr(transparent)]
pub struct SignatureEcdsaSecp256k1(pub [u8; 64]);
/// Sha2 digest with 256 bits (32 bytes).
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
#[repr(transparent)]
pub struct HashSha2256(pub [u8; 32]);
/// Sha3 digest with 256 bits (32 bytes).
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
#[repr(transparent)]
pub struct HashSha3256(pub [u8; 32]);
/// Keccak digest with 256 bits (32 bytes).
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
#[repr(transparent)]
pub struct HashKeccak256(pub [u8; 32]);
#[derive(Debug, Clone, Default)]
#[doc(hidden)]
pub struct ExternStateApi;
impl ExternStateApi {
/// Open the contract state. Only one instance can be opened at the same
/// time.
pub fn open() -> Self { Self }
}
/// Operations backed by host functions for the low-level interface.
#[doc(hidden)]
#[derive(Default)]
pub struct ExternLowLevelHost {
pub(crate) state_api: ExternStateApi,
pub(crate) state_builder: StateBuilder<ExternStateApi>,
}
/// Context backed by host functions.
#[derive(Default)]
#[doc(hidden)]
pub struct ExternContext<T: sealed::ContextType> {
marker: crate::marker::PhantomData<T>,
}
#[doc(hidden)]
pub struct ExternChainMeta {}
#[derive(Default)]
#[doc(hidden)]
pub struct ExternInitContext;
#[derive(Default)]
#[doc(hidden)]
pub struct ExternReceiveContext;
pub(crate) mod sealed {
use super::*;
/// Marker trait intended to indicate which context type we have.
/// This is deliberately a sealed trait, so that it is only implementable
/// by types in this crate.
pub trait ContextType {}
impl ContextType for ExternInitContext {}
impl ContextType for ExternReceiveContext {}
}
#[derive(Debug)]
/// The error type which is returned by methods on
/// [`HasStateApi`][`crate::HasStateApi`].
#[repr(u8)]
pub enum StateError {
/// The subtree is locked.
SubtreeLocked,
/// The entry does not exist.
EntryNotFound,
/// The iterator does not exist.
IteratorNotFound,
/// The parameter does not exist.
ParameterNotFound,
/// The specified size is too big.
SizeTooLarge,
/// The iterator limit for a prefix has been reached.
IteratorLimitForPrefixExceeded,
/// The iterator has already been deleted.
IteratorAlreadyDeleted,
/// No nodes exist with the given prefix.
SubtreeWithPrefixNotFound,
}