This repository has been archived by the owner on Aug 2, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
/
Copy patheos.hpp
375 lines (318 loc) · 14.1 KB
/
eos.hpp
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
extern "C" {
typedef long long int64_t;
typedef unsigned long long uint64_t;
typedef unsigned long uint32_t;
typedef long int32_t;
typedef unsigned __int128 uint128_t;
typedef __int128 int128_t;
typedef unsigned char uint8_t;
typedef uint64_t AccountName;
typedef uint64_t TableName;
typedef uint32_t Time;
/**
* @param msg - a pointer where up to @ref len bytes of the current message will be coppied
* @return the number of bytes copied to msg
*/
extern uint32_t readMessage( void* msg, uint32_t len );
/**
* This method is useful for dynamicly sized messages
*
* @return the length of the current message
*/
extern uint32_t messageSize();
/**
* @param scope - the account scope that will be read, must exist in the transaction scopes list
* @param table - the ID/name of the table within the current scope/code context to modify
* @param key - an key that can be used to lookup data in the table
*
* @return a unique ID assigned to this table record separate from the key, used for iterator access
*/
int32_t store_i64( AccountName scope, TableName table, uint64_t key, const void* data, uint32_t datalen );
/**
* @param scope - the account scope that will be read, must exist in the transaction scopes list
* @param code - identifies the code that controls write-access to the data
* @param table - the ID/name of the table within the scope/code context to query
* @param key - an key that can be used to lookup data in the table
* @param data - location to copy the data stored at key
* @param datalen - the maximum length of data to read
*
* @return the number of bytes read or -1 if key was not found
*/
int32_t load_i64( AccountName scope, AccountName code, TableName table, uint64_t key, void* data, uint32_t datalen );
int32_t remove_i64( AccountName scope, TableName table, uint64_t key );
/**
* These methods expect data to point to a record that is at least 2*sizeof(uint128_t) where the leading
* 32 bytes are the primary and secondary keys. These keys will be interpreted and sorted as unsigned
* 128 bit integers.
*
* @return the total number of bytes read or -1 for "not found" or "end".
*/
///@{
int32_t front_primary_i128i128( AccountName scope, AccountName code, TableName table, void* data, uint32_t len );
int32_t back_primary_i128i128( AccountName scope, AccountName code, TableName table, void* data, uint32_t len );
int32_t next_primary_i128i128( AccountName scope, AccountName code, TableName table, void* data, uint32_t len );
int32_t previous_primary_i128i128( AccountName scope, AccountName code, TableName table, void* data, uint32_t len );
int32_t front_secondary_i128i128( AccountName scope, AccountName code, TableName table, void* data, uint32_t len );
int32_t back_secondary_i128i128( AccountName scope, AccountName code, TableName table, void* data, uint32_t len );
int32_t next_secondary_i128i128( AccountName scope, AccountName code, TableName table, void* data, uint32_t len );
int32_t previous_secondary_i128i128( AccountName scope, AccountName code, TableName table, void* data, uint32_t len );
///@}
int32_t upper_bound_primary_i128i128( AccountName scope, AccountName code, TableName table,
const uint128_t* key, void* data, uint32_t len );
int32_t lower_bound_primary_i128i128( AccountName scope, AccountName code, TableName table,
const uint128_t* key, void* data, uint32_t len );
int32_t upper_bound_secondary_i128i128( AccountName scope, AccountName code, TableName table,
const uint128_t* key, void* data, uint32_t len );
int32_t lower_bound_secondary_i128i128( AccountName scope, AccountName code, TableName table,
const uint128_t* key, void* data, uint32_t len );
/// data must point to 2*sizeof(uint128) containing primary and secondary key
bool remove_i128i128( AccountName scope, TableName table, void* data );
/// data must point to at least 2*sizeof(uint128) containing primary and secondary key
bool store_i128i128( AccountName scope, TableName table, void* data, uint32_t len );
int32_t load_primary_i128i128( AccountName scope, AccountName code, TableName table, const void* primary, void* data, uint32_t len );
int32_t load_secondary_i128i128( AccountName scope, AccountName code, TableName table, const void* secondary, void* data, uint32_t len );
void print( const char* cstr );
void printi( uint64_t value );
/**
* @return the account which specifes the code that is being run
*/
AccountName currentCode();
void assert( uint32_t test, const char* cstr );
/**
* Verifies that @ref name exists in the set of notified accounts on a message. Throws if not found
*/
void requireNotice( AccountName );
/**
* Verifies that @ref name exists in the set of provided auths on a message. Throws if not found
*/
void requireAuth( AccountName name );
/**
* Gets the notified account at index N
*/
AccountName getNotify( int32_t index );
/**
* Gets the required auth at index N
*/
AccountName getAuth( int32_t index );
/**
* Returns the time of the last block (not the block including this message)
*/
uint32_t now();
/**
* Any message handler can generate an "output" to be returned if it calls the callResult() API, if
* callResult() is not called then result_length will be set to 0.
*
* @param code - the account whose code should execute within the notify account contexts
* @param notify - any account in the notify list must be within the current read scope
* @param message - the message that should be delivered
* @param result - a place to store the result of the call
*
* @param canfail - if true then a new undo context is started and undon on error, else this method throws on error
* @return 0 on success and 1 if the call aborted
*/
uint32_t syncCall( AccountName code, AccountName* authorities, uint32_t numauths,
AccountName* notify, uint32_t numnotice,
const void* message, uint32_t message_length,
void* result, uint32_t* result_length,
bool canfail );
/**
* Used to specify the return value for syncCall
*/
void callResult( const void* data, uint32_t datalen );
/**
* Given the message with CODE.ACTION notifying CONTEXT we normally also allow
* CONTEXT to define its own method handler that can be called: eg context::apply_code_action()
*
* In some cases the code::apply_code_action() may want to prevent context::apply_code_action()
* from being invoked. This is necessary if the context may have incentive to block a particular
* contract from modifying data stored in the context/code section.
*
* For example a social media website that stores votes on accounts and an account owner interested
* in blocking negative votes.
*/
void disableContextCode( uint64_t AccountName );
} /// extern C
template<typename T>
T min( const T& a, const T&b ) {
return a < b ? a : b;
}
static constexpr char char_to_symbol( char c ) {
if( c >= 'a' && c <= 'z' )
return (c - 'a') + 1;
if( c >= '1' && c <= '5' )
return (c - '1') + 26;
return 0;
}
static constexpr uint64_t string_to_name( const char* str ) {
uint32_t len = 0;
while( str[len] ) ++len;
uint64_t value = 0;
for( uint32_t i = 0; i <= 12 && i < len; ++i ) {
value <<= 5;
value |= char_to_symbol( str[ len -1 - i ] );
}
if( len == 13 ) {
value <<= 4;
value |= 0x0f & char_to_symbol( str[ 12 ] );
}
return value;
}
template<uint64_t I>
struct ConstName {
static uint64_t value() { return I; }
operator uint64_t()const { return I; }
};
#define NAME(X) (ConstName<string_to_name(X)>::value())
#define N(X) string_to_name(#X)
struct Name {
Name(){}
// Name( const char* c ) : value( string_to_name(c) ){}
Name( uint64_t v ): value(v) {}
operator uint64_t()const { return value; }
friend bool operator==( const Name& a, const Name& b ) { return a.value == b.value; }
AccountName value = 0;
};
struct Db
{
template<typename T>
static bool get( Name key, T& value ){
return get( currentCode(), key, value );
}
template<typename T>
static bool get( Name scope, Name key, T& value ){
return get( scope, currentCode(), key, value );
}
template<typename T>
static bool get( Name scope, Name code, Name key, T& result ) {
auto read = load_i64( scope.value, code.value, T::tableId().value, key.value, &result, sizeof(result) );
return read > 0;
}
template<typename T>
static int32_t store( Name key, const T& value ) {
return store( currentCode(), key, value );
}
template<typename T>
static int32_t store( Name scope, Name key, const T& value ) {
return store_i64( scope, T::tableId(), key, &value, sizeof(value) );
}
template<typename T>
static bool remove( Name scope, Name key ) {
return remove_i64( scope, T::tableId(), key );
}
template<typename T>
static bool remove( Name key ) {
return remove<T>( currentCode(), key );
}
};
template<typename T> struct remove_reference { typedef T type; };
template<typename T> struct remove_reference<T&> { typedef T type; };
template<typename T> struct remove_reference<const T&> { typedef T type; };
template<typename T>
T currentMessage() {
T value;
readMessage( &value, sizeof(value) );
return value;
}
template<typename... Accounts>
void requireNotice( AccountName name, Accounts... accounts ){
requireNotice( name );
requireNotice( accounts... );
}
struct Ratio {
uint64_t base = 1;
uint64_t quote = 1;
};
static_assert( sizeof(Ratio) == 2*sizeof(uint64_t), "unexpected padding" );
template<int Primary, int Secondary>
struct table_impl{};
template<>
struct table_impl<16,16> {
static int32_t front_primary( uint64_t scope, uint64_t code, uint64_t table, void* data, uint32_t len ) {
return front_primary_i128i128( scope, code, table, data, len );
}
static int32_t back_primary( uint64_t scope, uint64_t code, uint64_t table, void* data, uint32_t len ) {
return back_primary_i128i128( scope, code, table, data, len );
}
static bool remove( uint64_t scope, uint64_t table, void* data ) {
return remove_i128i128( scope, table, data );
}
static int32_t load_primary( uint64_t scope, uint64_t code, uint64_t table, const void* primary, void* data, uint32_t len ) {
return load_primary_i128i128( scope, code, table, primary, data, len );
}
static int32_t front_secondary( AccountName scope, AccountName code, TableName table, void* data, uint32_t len ) {
return front_secondary_i128i128( scope, code, table, data, len );
}
static int32_t back_secondary( AccountName scope, AccountName code, TableName table, void* data, uint32_t len ) {
return back_secondary_i128i128( scope, code, table, data, len );
}
static bool store( AccountName scope, TableName table, void* data, uint32_t len ) {
return store_i128i128( scope, table, data, len );
}
};
template<uint64_t scope, uint64_t code, uint64_t table, typename Record>
struct Table {
private:
typedef typename remove_reference<decltype( ((Record*)(nullptr))->primary() )>::type Primary;
typedef typename remove_reference<decltype( ((Record*)(nullptr))->secondary() )>::type Secondary;
typedef table_impl<sizeof( Primary ), sizeof( Secondary )> impl;
public:
struct PrimaryIndex {
static bool front( Record& r ) {
return impl::front_primary( scope, code, table, &r, sizeof(Record) ) == sizeof(Record);
}
static bool back( Record& r ) {
return impl::back_primary( scope, code, table, &r, sizeof(Record) ) == sizeof(Record);
}
static bool next( Record& r ) {
return impl::next_primary( scope, code, table, &r, sizeof(Record) ) == sizeof(Record);
}
static bool previous( Record& r ) {
return impl::previous_primary( scope, code, table, &r, sizeof(Record) ) == sizeof(Record);
}
static bool get( const Primary& p, Record& r ) {
return impl::load_primary( scope, code, table, &p, &r, sizeof(Record) ) == sizeof(Record);
}
static bool lower_bound( const Primary& p, Record& r ) {
return impl::lower_bound_primary( scope, code, table, &p &r, sizeof(Record) ) == sizeof(Record);
}
static bool upper_bound( const Primary& p, Record& r ) {
return impl::upper_bound_primary( scope, code, table, &p &r, sizeof(Record) ) == sizeof(Record);
}
static bool remove( Record& r ) {
impl::remove( scope, table, &r );
}
};
struct SecondaryIndex {
static bool front( Record& r ) {
return impl::front_secondary( scope, code, table, &r, sizeof(Record) ) == sizeof(Record);
}
static bool back( Record& r ) {
return impl::back_secondary( scope, code, table, &r, sizeof(Record) ) == sizeof(Record);
}
static bool next( Record& r ) {
return impl::next_secondary( scope, code, table, &r, sizeof(Record) ) == sizeof(Record);
}
static bool previous( Record& r ) {
return impl::previous_secondary( scope, code, table, &r, sizeof(Record) ) == sizeof(Record);
}
static bool get( const Primary& p, Record& r ) {
return impl::load_secondary( scope, code, table, &p &r, sizeof(Record) ) == sizeof(Record);
}
static bool lower_bound( const Primary& p, Record& r ) {
return impl::lower_bound_secondary( scope, code, table, &p &r, sizeof(Record) ) == sizeof(Record);
}
static bool upper_bound( const Primary& p, Record& r ) {
return impl::upper_bound_secondary( scope, code, table, &p &r, sizeof(Record) ) == sizeof(Record);
}
static bool remove( Record& r ) {
impl::remove( scope, table, &r );
}
};
static bool store( Record& r ) {
return impl::store( scope, table, &r, sizeof(r) );
}
static bool remove( Record& r ) {
return impl::remove( scope, table, &r );
}
};
#define TABLE(SCOPE, CODE, TABLE, TYPE) Table<N(SCOPE),N(CODE),N(TABLE),TYPE>