AGRIO.CDT is a toolchain for WebAssembly (WASM) and set of tools to facilitate contract writing for the AGRIO platform. In addition to being a general purpose WebAssembly toolchain, AGRIO specific optimizations are available to support building AGRIO smart contracts. This new toolchain is built around Clang 7, which means that AGRIO.CDT has the most currently available optimizations and analyses from LLVM, but as the WASM target is still considered experimental, some optimizations are not available or incomplete.
AGRIO.CDT Version 1.3.x introduced quite a few breaking changes. To have binary releases we needed to remove the concept of a core symbol from AGRIO.CDT. This meant drastic changes to symbol, asset and other types/functions that were connected to them. Since these changes would be disruptive, we decided to add as many disruptive changes needed for future contract writing, so that disruption should only occur once. Please read the Differences between Version 1.2.x and Version 1.3.x section of this readme.
AGRIO.CDT currently supports Mac OS X brew, Linux x86_64 Debian packages, and Linux x86_64 RPM packages.
If you have previously installed AGRIO.CDT, please run the uninstall
script (it is in the directory where you cloned AGRIO.CDT) before downloading and using the binary releases.
$ brew tap agrio/agrio.cdt
$ brew install agrio.cdt
$ brew remove agrio.cdt
$ wget https://github.com/agrio/agrio.cdt/releases/download/v1.4.1/agrio.cdt-1.4.1.x86_64.deb
$ sudo apt install ./agrio.cdt-1.4.1.x86_64.deb
$ sudo apt remove agrio.cdt
$ wget https://github.com/agrio/agrio.cdt/releases/download/v1.4.1/agrio.cdt-fedora-1.4.1.x86_64-0.x86_64.rpm
$ sudo yum install ./agrio.cdt-fedora-1.4.1.x86_64-0.x86_64.rpm
$ sudo yum remove agrio.cdt
$ wget https://github.com/agrio/agrio.cdt/releases/download/v1.4.1/agrio.cdt-centos-1.4.1.x86_64-0.x86_64.rpm
$ sudo yum install ./agrio.cdt-centos-1.4.1.x86_64-0.x86_64.rpm
$ sudo yum remove agrio.cdt
$ git clone --recursive https://github.com/agrio/agrio.cdt
$ cd agrio.cdt
$ ./build.sh
$ sudo ./install.sh
- Navigate to the hello folder in examples (./examples/hello).
- You should then see the hello.cpp file
- Now run the compiler
$ agrio-cpp -abigen hello.cpp -o hello.wasm
- Or with CMake
$ mkdir build
$ cd build
$ cmake ..
$ make
This will generate two files:
- The compiled binary wasm (hello.wasm)
- The generated ABI file (hello.abi)
To generate an ABI with agrio-abigen
, only requires that you give the main '.cpp' file to compile and the output filename --output
and generating against the contract name --contract
.
Example:
$ agrio-abigen hello.cpp --contract=hello --output=hello.abi
This will generate one file:
- The generated ABI file (hello.abi)
- Removed the following typedefs to
uint64_t
:account_name
permission_name
scope_name
table_name
action_name
- Added a
uint64_t
typedef calledcapi_name
to replace the removed typedefs above:- These have been replaced by
capi_name
and as a practice should not be used when writing C++ contract code. Instead, the new version of theagrio::name
type from the agriolib C++ API should be used to replace these instances. This decision was made because of bad implicit casting issues withuint64_t
and the new pattern should allow for better type safety.
- These have been replaced by
- Removed
symbol_name
typedef:- This has no C equivalent to replace it. When writing C++ contract code, the
agrio::symbol_code
struct should be used instead. As with the previously mentioned named types, this was removed and replaced withagrio::symbol_code
to allow for better type safety in contracts. To use a symbol, i.e. symbol name and precision, use theagrio::symbol
class.
- This has no C equivalent to replace it. When writing C++ contract code, the
- Removed
time
andweight_type
typedefs. - Removed the
transaction_id_type
andblock_id_type
typedefs. - Removed the
account_permission
struct. - Renamed the following typedefs:
checksum160
->capi_checksum160
checksum256
->capi_checksum256
checksum512
->capi_checksum512
public_key
->capi_public_key
signature
->capi_signature
- Removed the non-existent intrinsics declarations
require_write_lock
andrequire_read_lock
.
- Removed agriolib/vector.hpp:
- Removed alias
agrio::vector
and typedefbytes
. - Going forward contract writers should include
<vector>
from the STL and usestd::vector<char>
instead of bytes.
- Removed alias
- Removed agriolib/types.hpp.
- Removed agriolib/optional.hpp. Use
std::optional
as a replacement. - Removed agriolib/core_symbol.hpp. The contract writer should explicitly specify the symbol.
- Added agriolib/name.hpp.
- Moved the typedef
agrio::extensions_types
to agriolib/transaction.hpp. - Removed comparison functions for
checksum
structs. - Removal of
agrio::char_to_symbol
,agrio::string_to_name
,agrio::name_suffix
functions - Removal of the
N
macro. The""_n
operator or thename
constructor should be used as a type safe replacement. Example:N(foo)
->"foo"_n
, orN(foo)
->name("foo")
. - Moved
agrio::name
struct definition and""_n
operator to agriolib/name.hpp.
- Removed implicit and explicit conversions to
uint64_t
. - Added
enum class
agrio::name::raw
which is implicitly converted from anagrio::name
(used for template non-type parameters). - Added
bool
conversion operator for conditionally testing if a name is empty. - All constructors are now
constexpr
. These take either auint64_t
, anagrio::name::raw
or astd::string_view
. - Added
constexpr
methodsagrio::name::length
andagrio::name::suffix
. - Added equivalence, inverted equivalence and less than operators to
agrio::name
.
- Removed
agrio::symbol_type
struct and replaced withagrio::symbol
class. - Added struct
agrio::symbol_code
:- Added two
constexpr
constructors that take either a rawuint64_t
or anstd::string_view
. - Added
constexpr
methodsis_valid
,length
andraw
. - Added a print method.
- Added
bool
conversion operator to test issymbol_code
is empty.
- Added two
- Removed
agrio::string_to_symbol
,agrio::is_valid_symbol
,agrio::symbol_name_length
functions. - Removed the
S
macro. The symbol constructor should be used as a type safe replacement. Example:S(4,SYS)
->symbol(symbol_code("SYS"), 4)
(or simplysymbol("SYS", 4)
as of v1.3.1). - Added struct
agrio::symbol
:- Added three
constexpr
constructors that take either a rawuint64_t
,symbol_code
and auint8_t
precision or anstd::string_view
and auint8_t
precision. - Added
constexpr
methodsis_valid
,precision
,code
, andraw
. These, respectively, check if thesymbol
is valid, get theuint8_t
precision, get thesymbol_code
part of thesymbol
, and get the rawuint64_t
representation ofsymbol
. - Added equivalence, inverted equivalence and less than operators to
agrio::symbol
.
- Added three
- Modified struct
agrio::extended_symbol
:- Restricted fields to private.
- Added
constexpr
constructor that takes aagrio::symbol
and anagrio::name
. - Added
constexpr
methodsget_symbol
andget_contract
. - Made existing comparison operators
constexpr
.
- The main constructor now requires a
int64_t
(quantity) andagrio::symbol
explicitly. - The default constructor no longer initializes the instance to a valid zero quantity asset with a symbol equivalent to "core symbol". Instead the default constructed
agrio::asset
is a bit representation of all zeros (which will causeis_valid
to fail) so that check is bypassed to allow formulti_index
anddatastream
to work. - Old contracts that use
agrio::asset()
should be changed to either use the core symbol of the specific chain they are targeting i.e.agrio::asset(0, symbol(symbol_code("SYS"),4))
. To reduce writingsymbol(symbol_code("SYS"),4)
over and over, aconstexpr
function to return the symbol orconstexpr
global variable should be used.
- The constructor for
agrio::contract
now takes anagrio::name
for the receiver, anagrio::name
for the code, and aagrio::datastream<const char*>
for the datastream used for the contract. The last argument is for manually unpacking an action, see the section onagrio::ignore
for a more indepth usage.
- Renamed the macro
AGRIO_ABI
toAGRIO_DISPATCH
as this is more descriptive of what this macro actually does. - Modified the definition of
AGRIO_DISPATCH
to work with the new constructor foragrio::contract
.
- The first template parameter for
indexed_by
now requires the argument be convertible toagrio::name::raw
(replacinguint64_t
). - The first template parameter for
multi_index
now requires the argument be convertible toagrio::name::raw
(replacinguint64_t
). - The constructor now takes an
agrio::name
type for the code (replacinguint64_t
). Scope is stilluint64_t
. - Various other replacements of
uint64_t
toagrio::name
.
- The first template parameter for
agrio::singleton
now requires the argument be convertible toagrio::name::raw
(replacinguint64_t
). - The constructor now takes an
agrio::name
type for the code. - In the methods
get_or_create
andset
, the argumentbill_to_account
is now of typeagrio::name
(replacinguint64_t
).
- Added C++ function
agrio::require_auth
. - Added C++ function
agrio::has_auth
. - Added C++ function
agrio::is_account
. - Redefined
agrio::permission_level
to useagrio::name
in place ofuint64_t
. - Removed the macro
ACTION
. (The identifierACTION
has been reused for another macro described below in the Macros section.)
- The optional provided_keys argument of the function
agrio::check_transaction_authorization
is now of the typestd::set<agrio::public_key>
rather than the typestd::set<capi_public_key>
. C++ contract code should most likely be using theagrio::public_key
struct (defined in "agriolib/public_key.hpp") if they need to deal with AGRIO-compatible public keys rather than thecapi_public_key
struct (now renamed from its original name of::public_key
) from the agriolib C API. Note that existing contract code that just referred to the typepublic_key
without namespace qualification may have accidentally been using thecapi_public_key
struct and therefore should ideally be modified to use theagrio::public_key
C++ type. - The
account
andpermission
arguments ofagrio::check_permission_authorization
are bothagrio::name
now instead ofuint64_t
.
- Added new type
ignore
:- This type acts as a placeholder for actions that don't want to deserialize their fields but want the types to be reflected in the ABI.
ACTION action(ignore<some_type>) { some_type st; _ds >> st; }
- This type acts as a placeholder for actions that don't want to deserialize their fields but want the types to be reflected in the ABI.
- Added new type
ignore_wrapper
:- This allows for calling
SEND_INLINE_ACTION
withignore_wrapper(some_value)
against an action with anignore
of matching types.
- This allows for calling
- Added
ACTION
macro which is simply a shortcut for[[agrio::action]] void
. - Added
TABLE
macro which is simply a shortcut forstruct [[agrio::table]]
. - Added
CONTRACT
macro which is simply a shortcut forclass [[agrio::contract]]
.
- Added
agrio.cdt-config.cmake
to allow forfind_package(agrio.cdt)
. See agrio.cdt/examples/hello or agrio.cdt/examples/template for an example. - Added new macro
add_contract
. This new contract takes a contract name, cmake target, then any normal arguments you would give toadd_executable
. See agrio.cdt/examples/hello or agrio.cdt/examples/template. - New version checking mechanism is included. See agrio.contracts/CMakeLists.txt to see this in use.
- Replaced
printf
,sprintf
, andsnprintf
with new minimal variants. This allows contracts to use these functions without causing stack overflow issues.
- Removed
sstream
with the intent to return this after more has been done. - Added
__cxa_pure_virtual
to allow for pure virtual methods in contract classes. std::to_string
now works without the issues of stack overflows.
- Added
[[agrio::ignore]]
attribute to flag a type as being ignored by the deserializer. This attribute is primarily only used for internal use within agriolib. - Added
[[agrio::contract]]
attribute. This new attribute is used to mark a contract class as "contract" with the name being either the C++ name of the class or a user specified name (i.e.[[agrio::contract("somecontract")]]
). This attribute can also be used in conjunction with theagrio::action
andagrio::table
attributes for tables that you would like to define outside of theagrio::contract
class. This is used in conjunction with either the rawagrio-cpp
option--contract <name>
,-o <name>.wasm
or with CMakeadd_contract
. It acts as a filter enabling contract developers to include a header file with attributes from another contract (e.g. agrio.token) while generating an ABI devoid of those actions and tables.The above code will produce the tables#include <agriolib/agrio.hpp> using namespace agrio; CONTRACT test : public agrio::contract { public: using contract::contract; ACTION acta(){} TABLE taba { uint64_t a; float b; uint64_t primary_key() const { return a; } }; }; struct [[agrio::table, agrio::contract("test")]] tabb { uint64_t a; int b; }; typedef agrio::multi_index<"testtaba"_n, test::taba> table_a; typedef agrio::multi_index<"testtabb"_n, tabb> table_b; AGRIO_DISPATCH( test, (acta) )
testtaba
andtesttabb
in your ABI. Example:agrio-cpp -abigen test.cpp -o test.wasm
will mark this compilation and ABI generation for theagrio::contract
test
. The same thing can be done withagrio-cpp -abigen test.cpp -o test_contract.wasm --contract test
or with the CMake commandadd_contract( test, test_contract, test.cpp )
. Either of the previous two approaches will produce a test_contract.wasm and test_contract.abi generated under the context of the contract name oftest
.
- Boost is now part of the library. No more external dependence on Boost and all system inclusion are within it's
sysroot
. (Boost will be removed in a future release.)
Unlike the old ABI generator tool, the new tool uses C++11 or GNU style attributes to mark actions
and tables
.
This attribute marks either a struct or a method as an action. Example (four ways to declare an action for ABI generation):
// this is the C++11 and greater style attribute
[[agrio::action]]
void testa( name n ) {
// do something
}
// this is the GNU style attribute, this can be used in C code and prior to C++ 11
__attribute__((agrio_action))
void testa( name n ){
// do something
}
struct [[agrio::action]] testa {
name n;
AGRLIB_SERIALIZE( testa, (n) )
};
struct __attribute__((agrio_action)) testa {
name n;
AGRLIB_SERIALIZE( testa, (n) )
};
You can explicitly specify the name in the attribute c++ [[agrio::action("<valid action name>")]]
Example (two ways to declare a table for ABI generation):
struct [[agrio::table]] testtable {
uint64_t owner;
/* all other fields */
};
struct __attribute__((agrio_table)) testtable {
uint64_t owner;
/* all other fields */
};
typedef agrio::multi_index<"tablename"_n, testtable> testtable_t;
If you don't want to use the multi-index you can explicitly specify the name in the attribute c++ [[agrio::table("<valid action name>")]]
.
For an example contract of ABI generation please see the file ./examples/abigen_test/test.cpp. You can generate the ABI for this file with agrio-abigen test.cpp --output=test.abi
.
- The sections to the ABI are pretty simple to understand and the syntax is purely JSON, so it is reasonable to write an ABI file manually.
- The ABI generation will never be completely perfect for every contract written. Advanced features of the newest version of the ABI will require manual construction of the ABI, and odd and advanced C++ patterns could capsize the generators type deductions. So having a good knowledge of how to write an ABI should be an essential piece of knowledge of a smart contract writer.
- As of AGRIO.CDT v1.4.0 the ABI generator will try to automatically import contracts and clauses into the generated ABI. There are a few caveats to this, one is a strict naming policy of the files and an HTML tag used to mark each Ricardian contract and each clause.
- The Ricardian contracts should be housed in a file with the name .contracts.md and the clauses should be in a file named .clauses.md.
- For each Ricardian contract the header
<h1 class="contract">ActionName</h1>
should be used, as this directs the ABI generator to attach this Ricardian contract to the specified action. - For each Ricardian clause the header
<h1 class="clause">ClauseID</h1>
should be used, as this directs the ABI generator to the clause id and the subsequent body. - The option
-R
has been added to agrio-cpp and agrio-abigen to add "resource" paths to search from, so you can place these files in any directory structure you like and use-R<path to file>
in the same vein as-I
for include paths. - To see these in use please see ./examples/hello/hello.contracts.md and ./examples/hello/hello.clauses.md.
- agrio-cpp
- agrio-cc
- agrio-ld
- agrio-abigen
- agrio-pp (post processing pass for WASM, automatically runs with agrio-cpp and agrio-ld)
- agrio-wasm2wast
- agrio-wast2wasm
- agrio-ranlib
- agrio-ar
- agrio-objdump
- agrio-readelf
To compile an AGRIO smart contract, the preferred method is to use the template CMakeLists.txt in the examples folder.
For example:
In CMakeLists.txt
:
cmake_minimum_required(VERSION 3.5)
project(test_example VERSION 1.0.0)
find_package(agrio.cdt)
add_contract( test test test.cpp )
In test.cpp
:
#include <agriolib/agrio.hpp>
using namespace agrio;
CONTRACT test : public agrio::contract {
public:
using contract::contract;
ACTION testact( name test ) {
}
};
AGRIO_DISPATCH( test, (testact) )
To manually compile the source code, use agrio-cpp/agrio-cc
and agrio-ld
as if it were clang and lld. All the includes and options specific to AGRIO and CDT are baked in.
OVERVIEW: agrio-cpp (Agrio C++ -> WebAssembly compiler)
USAGE: agrio-cpp [options] <input file> ...
OPTIONS:
-C - Include comments in preprocessed output
-CC - Include comments from within macros in preprocessed output
-D=<string> - Define <macro> to <value> (or 1 if <value> omitted)
-E - Only run the preprocessor
-I=<string> - Add directory to include search path
-L=<string> - Add directory to library search path
-O=<string> - Optimization level s, 0-3
-S - Only run preprocess and compilation steps
-U=<string> - Undefine macro <macro>
-W=<string> - Enable the specified warning
-c - Only run preprocess, compile, and assemble steps
-dD - Print macro definitions in -E mode in addition to normal output
-dI - Print include directives in -E mode in addition to normal outpu
-dM - Print macro definitions in -E mode instead to normal output
-emit-ast - Emit Clang AST files for source inputs
-emit-llvm - Use the LLVM representation for assembler and object files
-faligned-allocation - Enable C++17 aligned allocation functions
-fcoroutine-ts - Enable support for the C++ Coroutines TS
-finline-functions - Inline suitable functions
-finline-hint-functions - Inline functions which are (explicitly or implicitly) marked inline
-fmerge-all-constants - Allow merging of constants
-fno-cfl-aa - Disable CFL Alias Analysis
-fno-elide-constructors - Disable C++ copy constructor elision
-fno-lto - Disable LTO
-fstack-protector - Enable stack protectors for functions potentially vulnerable to stack smashing
-fstack-protector-all - Force the usage of stack protectors for all functions
-fstack-protector-strong - Use a strong heuristic to apply stack protectors to functions
-fstrict-enums - Enable optimizations based on the strict definition of an enum's value range
-fstrict-return - Always treat control flow paths that fall off the end of a non-void function as unreachable
-fstrict-vtable-pointers - Enable optimizations based on the strict rules for overwriting polymorphic C++ objects
-include=<string> - Include file before parsing
-isysroot=<string> - Set the system root directory (usually /)
-l=<string> - Root name of library to link
-lto-opt=<string> - LTO Optimization level (O0-O3)
-o=<string> - Write output to <file>
-std=<string> - Language standard to compile for
-v - Show commands to run and use verbose output
-w - Suppress all warnings
Generic Options:
-help - Display available options (-help-hidden for more)
-help-list - Display list of available options (-help-list-hidden for more)
-version - Display the version of this program
OVERVIEW: agrio-ld (WebAssembly linker)
USAGE: agrio-ld [options] <input file> ...
OPTIONS:
Generic Options:
-help - Display available options (-help-hidden for more)
-help-list - Display list of available options (-help-list-hidden for more)
-version - Display the version of this program
agrio.ld options:
-L=<string> - Add directory to library search path
-fno-cfl-aa - Disable CFL Alias Analysis
-fno-lto - Disable LTO
-fno-post-pass - Don't run post processing pass
-fno-stack-first - Don't set the stack first in memory
-l=<string> - Root name of library to link
-lto-opt=<string> - LTO Optimization level (O0-O3)
-o=<string> - Write output to <file>
USAGE: agrio-abigen [options] <source0> [... <sourceN>]
OPTIONS:
Generic Options:
-help - Display available options (-help-hidden for more)
-help-list - Display list of available options (-help-list-hidden for more)
-version - Display the version of this program
agrio-abigen:
generates an ABI from C++ project input
-extra-arg=<string> - Additional argument to append to the compiler command line
-extra-arg-before=<string> - Additional argument to prepend to the compiler command line
-output=<string> - Set the output filename and fullpath
-p=<string> - Build path
MIT