Skip to content
This repository was archived by the owner on Aug 30, 2022. It is now read-only.

Commit 0ebd5f3

Browse files
author
John DeBord
authored
Merge pull request #517 from EOSIO/1.8.3-oob-patch
Amend `release/1.8.3-oob`
2 parents c097d54 + 301c901 commit 0ebd5f3

2 files changed

Lines changed: 374 additions & 132 deletions

File tree

contracts/eosio.msig/include/eosio.msig/eosio.msig.hpp

Lines changed: 249 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,219 @@
66
#include <eosio/transaction.hpp>
77

88
namespace eosio {
9-
109
/**
11-
* @defgroup eosiomsig eosio.msig
12-
* @ingroup eosiocontracts
13-
* eosio.msig contract defines the structures and actions needed to manage the proposals and approvals on blockchain.
14-
* @{
10+
* Clone of `eosio::binary_extension` that includes `operator=` to avoid
11+
* bumping the `eosio.cdt` dependency version of the v1.8.x patch release of
12+
* `eosio.contracts`.
13+
*/
14+
template <typename T>
15+
class eosio_msig_binary_extension {
16+
public:
17+
using value_type = T;
18+
19+
constexpr eosio_msig_binary_extension() {}
20+
constexpr eosio_msig_binary_extension( const T& ext )
21+
:_has_value(true)
22+
{
23+
::new (&_data) T(ext);
24+
}
25+
constexpr eosio_msig_binary_extension( T&& ext )
26+
:_has_value(true)
27+
{
28+
::new (&_data) T(std::move(ext));
29+
}
30+
/** construct contained type in place */
31+
template <typename... Args>
32+
constexpr eosio_msig_binary_extension( std::in_place_t, Args&&... args )
33+
:_has_value(true)
34+
{
35+
::new (&_data) T(std::forward<Args>(args)...);
36+
}
37+
38+
constexpr eosio_msig_binary_extension( const eosio_msig_binary_extension& other )
39+
:_has_value(other._has_value)
40+
{
41+
if( other._has_value ) ::new (&_data) T( *other );
42+
}
43+
44+
constexpr eosio_msig_binary_extension( eosio_msig_binary_extension&& other )
45+
:_has_value(other._has_value)
46+
{
47+
if( other._has_value ) {
48+
::new (&_data) T( *std::move(other) );
49+
other._has_value = false;
50+
}
51+
}
52+
53+
/// @cond INTERNAL
54+
~eosio_msig_binary_extension() { reset(); }
55+
56+
/// @cond INTERNAL
57+
constexpr eosio_msig_binary_extension& operator= (const eosio_msig_binary_extension& other) {
58+
if (has_value())
59+
reset();
60+
61+
if (other.has_value()) {
62+
::new (&_data) T(*other);
63+
_has_value = true;
64+
}
65+
return *this;
66+
}
67+
68+
/// @cond INTERNAL
69+
constexpr eosio_msig_binary_extension& operator= (eosio_msig_binary_extension&& other) {
70+
if (has_value())
71+
reset();
72+
73+
if (other.has_value()) {
74+
::new (&_data) T(*other);
75+
_has_value = true;
76+
other._has_value = false;
77+
}
78+
return *this;
79+
}
80+
/** test if container is holding a value */
81+
constexpr explicit operator bool()const { return _has_value; }
82+
/** test if container is holding a value */
83+
constexpr bool has_value()const { return _has_value; }
84+
85+
/** get the contained value */
86+
constexpr T& value()& {
87+
if (!_has_value) {
88+
check(false, "cannot get value of empty eosio_msig_binary_extension");
89+
}
90+
return _get();
91+
}
92+
93+
/// @cond INTERNAL
94+
95+
/** get the contained value */
96+
constexpr const T& value()const & {
97+
if (!_has_value) {
98+
check(false, "cannot get value of empty eosio_msig_binary_extension");
99+
}
100+
return _get();
101+
}
102+
103+
/** get the contained value or a user specified default
104+
* @pre def should be convertible to type T
105+
* */
106+
template <typename U>
107+
constexpr auto value_or( U&& def ) -> std::enable_if_t<std::is_convertible<U, T>::value, T&>& {
108+
if (_has_value)
109+
return _get();
110+
return def;
111+
}
112+
113+
constexpr T value_or() const { return (_has_value) ? _get() : T{}; }
114+
115+
constexpr T* operator->() {
116+
return &_get();
117+
}
118+
constexpr const T* operator->()const {
119+
return &_get();
120+
}
121+
122+
constexpr T& operator*()& {
123+
return _get();
124+
}
125+
constexpr const T& operator*()const& {
126+
return _get();
127+
}
128+
constexpr const T&& operator*()const&& {
129+
return std::move(_get());
130+
}
131+
constexpr T&& operator*()&& {
132+
return std::move(_get());
133+
}
134+
135+
template<typename ...Args>
136+
T& emplace(Args&& ... args)& {
137+
if (_has_value) {
138+
reset();
139+
}
140+
141+
::new (&_data) T( std::forward<Args>(args)... );
142+
_has_value = true;
143+
144+
return _get();
145+
}
146+
147+
void reset() {
148+
if( _has_value ) {
149+
_get().~value_type();
150+
_has_value = false;
151+
}
152+
}
153+
154+
/// @endcond
155+
156+
private:
157+
bool _has_value = false;
158+
typename std::aligned_storage<sizeof(T), alignof(T)>::type _data;
159+
160+
constexpr T& _get() {
161+
return *reinterpret_cast<T*>(&_data);
162+
}
163+
164+
constexpr const T& _get()const {
165+
return *reinterpret_cast<const T*>(&_data);
166+
}
167+
};
168+
169+
/// @cond IMPLEMENTATIONS
170+
171+
/**
172+
* Serialize a eosio_msig_binary_extension into a stream
173+
*
174+
* @ingroup eosio_msig_binary_extension
175+
* @brief Serialize a eosio_msig_binary_extension
176+
* @param ds - The stream to write
177+
* @param opt - The value to serialize
178+
* @tparam DataStream - Type of datastream buffer
179+
* @return DataStream& - Reference to the datastream
180+
*/
181+
template<typename DataStream, typename T>
182+
inline DataStream& operator<<(DataStream& ds, const eosio::eosio_msig_binary_extension<T>& be) {
183+
ds << be.value_or();
184+
return ds;
185+
}
186+
187+
/**
188+
* Deserialize a eosio_msig_binary_extension from a stream
189+
*
190+
* @ingroup eosio_msig_binary_extension
191+
* @brief Deserialize a eosio_msig_binary_extension
192+
* @param ds - The stream to read
193+
* @param opt - The destination for deserialized value
194+
* @tparam DataStream - Type of datastream buffer
195+
* @return DataStream& - Reference to the datastream
196+
*/
197+
template<typename DataStream, typename T>
198+
inline DataStream& operator>>(DataStream& ds, eosio::eosio_msig_binary_extension<T>& be) {
199+
if( ds.remaining() ) {
200+
T val;
201+
ds >> val;
202+
be.emplace(val);
203+
}
204+
return ds;
205+
}
206+
207+
/**
208+
* The `eosio.msig` system contract allows for creation of proposed transactions which require authorization from a list of accounts, approval of the proposed transactions by those accounts required to approve it, and finally, it also allows the execution of the approved transactions on the blockchain.
209+
*
210+
* In short, the workflow to propose, review, approve and then executed a transaction it can be described by the following:
211+
* - first you create a transaction json file,
212+
* - then you submit this proposal to the `eosio.msig` contract, and you also insert the account permissions required to approve this proposal into the command that submits the proposal to the blockchain,
213+
* - the proposal then gets stored on the blockchain by the `eosio.msig` contract, and is accessible for review and approval to those accounts required to approve it,
214+
* - after each of the appointed accounts required to approve the proposed transactions reviews and approves it, you can execute the proposed transaction. The `eosio.msig` contract will execute it automatically, but not before validating that the transaction has not expired, it is not cancelled, and it has been signed by all the permissions in the initial proposal's required permission list.
15215
*/
16216
class [[eosio::contract("eosio.msig")]] multisig : public contract {
17217
public:
18218
using contract::contract;
19219

20220
/**
21-
* Create proposal
22-
*
23-
* @details Creates a proposal containing one transaction.
221+
* Propose action, creates a proposal containing one transaction.
24222
* Allows an account `proposer` to make a proposal `proposal_name` which has `requested`
25223
* permission levels expected to approve the proposal, and if approved by all expected
26224
* permission levels then `trx` transaction can we executed by this proposal.
@@ -36,13 +234,10 @@ namespace eosio {
36234
* @param trx - Proposed transaction
37235
*/
38236
[[eosio::action]]
39-
void propose(ignore<name> proposer, ignore<name> proposal_name,
40-
ignore<std::vector<permission_level>> requested, ignore<transaction> trx);
237+
void propose(name proposer, name proposal_name,
238+
std::vector<permission_level> requested, ignore<transaction> trx);
41239
/**
42-
* Approve proposal
43-
*
44-
* @details Approves an existing proposal
45-
* Allows an account, the owner of `level` permission, to approve a proposal `proposal_name`
240+
* Approve action approves an existing proposal. Allows an account, the owner of `level` permission, to approve a proposal `proposal_name`
46241
* proposed by `proposer`. If the proposal's requested approval list contains the `level`
47242
* permission then the `level` permission is moved from internal `requested_approvals` list to
48243
* internal `provided_approvals` list of the proposal, thus persisting the approval for
@@ -57,10 +252,7 @@ namespace eosio {
57252
void approve( name proposer, name proposal_name, permission_level level,
58253
const eosio::binary_extension<eosio::checksum256>& proposal_hash );
59254
/**
60-
* Revoke proposal
61-
*
62-
* @details Revokes an existing proposal
63-
* This action is the reverse of the `approve` action: if all validations pass
255+
* Unapprove action revokes an existing proposal. This action is the reverse of the `approve` action: if all validations pass
64256
* the `level` permission is erased from internal `provided_approvals` and added to the internal
65257
* `requested_approvals` list, and thus un-approve or revoke the proposal.
66258
*
@@ -71,9 +263,7 @@ namespace eosio {
71263
[[eosio::action]]
72264
void unapprove( name proposer, name proposal_name, permission_level level );
73265
/**
74-
* Cancel proposal
75-
*
76-
* @details Cancels an existing proposal
266+
* Cancel action cancels an existing proposal.
77267
*
78268
* @param proposer - The account proposing a transaction
79269
* @param proposal_name - The name of the proposal (should be an existing proposal)
@@ -86,9 +276,7 @@ namespace eosio {
86276
[[eosio::action]]
87277
void cancel( name proposer, name proposal_name, name canceler );
88278
/**
89-
* Execute proposal
90-
*
91-
* @details Allows an `executer` account to execute a proposal.
279+
* Exec action allows an `executer` account to execute a proposal.
92280
*
93281
* Preconditions:
94282
* - `executer` has authorization,
@@ -107,9 +295,7 @@ namespace eosio {
107295
[[eosio::action]]
108296
void exec( name proposer, name proposal_name, name executer );
109297
/**
110-
* Invalidate proposal
111-
*
112-
* @details Allows an `account` to invalidate itself, that is, its name is added to
298+
* Invalidate action allows an `account` to invalidate itself, that is, its name is added to
113299
* the invalidations table and this table will be cross referenced when exec is performed.
114300
*
115301
* @param account - The account invalidating the transaction
@@ -123,52 +309,50 @@ namespace eosio {
123309
using cancel_action = eosio::action_wrapper<"cancel"_n, &multisig::cancel>;
124310
using exec_action = eosio::action_wrapper<"exec"_n, &multisig::exec>;
125311
using invalidate_action = eosio::action_wrapper<"invalidate"_n, &multisig::invalidate>;
312+
};
126313

127-
private:
128-
struct [[eosio::table]] proposal {
129-
name proposal_name;
130-
std::vector<char> packed_transaction;
131-
132-
uint64_t primary_key()const { return proposal_name.value; }
133-
};
134-
135-
typedef eosio::multi_index< "proposal"_n, proposal > proposals;
314+
struct [[eosio::table]] proposal {
315+
name proposal_name;
316+
std::vector<char> packed_transaction;
317+
eosio::eosio_msig_binary_extension< std::optional<time_point> > earliest_exec_time;
136318

137-
struct [[eosio::table]] old_approvals_info {
138-
name proposal_name;
139-
std::vector<permission_level> requested_approvals;
140-
std::vector<permission_level> provided_approvals;
319+
uint64_t primary_key()const { return proposal_name.value; }
320+
};
321+
typedef eosio::multi_index< "proposal"_n, proposal > proposals;
141322

142-
uint64_t primary_key()const { return proposal_name.value; }
143-
};
144-
typedef eosio::multi_index< "approvals"_n, old_approvals_info > old_approvals;
323+
struct [[eosio::table]] old_approvals_info {
324+
name proposal_name;
325+
std::vector<permission_level> requested_approvals;
326+
std::vector<permission_level> provided_approvals;
145327

146-
struct approval {
147-
permission_level level;
148-
time_point time;
149-
};
328+
uint64_t primary_key()const { return proposal_name.value; }
329+
};
330+
typedef eosio::multi_index< "approvals"_n, old_approvals_info > old_approvals;
150331

151-
struct [[eosio::table]] approvals_info {
152-
uint8_t version = 1;
153-
name proposal_name;
154-
//requested approval doesn't need to cointain time, but we want requested approval
155-
//to be of exact the same size ad provided approval, in this case approve/unapprove
156-
//doesn't change serialized data size. So, we use the same type.
157-
std::vector<approval> requested_approvals;
158-
std::vector<approval> provided_approvals;
332+
struct approval {
333+
permission_level level;
334+
time_point time;
335+
};
159336

160-
uint64_t primary_key()const { return proposal_name.value; }
161-
};
162-
typedef eosio::multi_index< "approvals2"_n, approvals_info > approvals;
337+
struct [[eosio::table]] approvals_info {
338+
uint8_t version = 1;
339+
name proposal_name;
340+
//requested approval doesn't need to contain time, but we want requested approval
341+
//to be of exactly the same size as provided approval, in this case approve/unapprove
342+
//doesn't change serialized data size. So, we use the same type.
343+
std::vector<approval> requested_approvals;
344+
std::vector<approval> provided_approvals;
163345

164-
struct [[eosio::table]] invalidation {
165-
name account;
166-
time_point last_invalidation_time;
346+
uint64_t primary_key()const { return proposal_name.value; }
347+
};
348+
typedef eosio::multi_index< "approvals2"_n, approvals_info > approvals;
167349

168-
uint64_t primary_key() const { return account.value; }
169-
};
350+
struct [[eosio::table]] invalidation {
351+
name account;
352+
time_point last_invalidation_time;
170353

171-
typedef eosio::multi_index< "invals"_n, invalidation > invalidations;
354+
uint64_t primary_key() const { return account.value; }
172355
};
173-
/** @}*/ // end of @defgroup eosiomsig eosio.msig
356+
typedef eosio::multi_index< "invals"_n, invalidation > invalidations;
357+
174358
} /// namespace eosio

0 commit comments

Comments
 (0)