diff --git a/.vimrc b/.vimrc new file mode 100644 index 00000000..deeafae2 --- /dev/null +++ b/.vimrc @@ -0,0 +1,6 @@ +set tabstop=3 +set expandtab +set shiftwidth=3 +"set autoindent +"set smartindent +"set cindent diff --git a/Rakefile b/Rakefile index cf0b3439..e517668b 100644 --- a/Rakefile +++ b/Rakefile @@ -5,6 +5,8 @@ require 'json' require 'bigdecimal' require 'shellwords' require 'rake/testtask' +import 'tasks/contracts.rake' +import 'tasks/lazy_wallets.rake' autoload :Xgt, 'xgt/ruby' autoload :Etc, 'etc' @@ -19,8 +21,12 @@ end directory "../xgt-build" +def from_genesis? + ENV['FROM_GENESIS']&.upcase == 'TRUE' +end + def mining_disabled? - ENV['MINING_DISABLED']&.upcase == 'TRUE' + ENV['MINING_DISABLED']&.upcase == 'FALSE' end def mining_threads @@ -74,6 +80,10 @@ def instance_index ENV['XGT_INSTANCE_INDEX'].to_i end +def port_offset + ENV['XGT_PORT_OFFSET'].to_i +end + def config rpc.call('database_api.get_config', {}) end @@ -114,7 +124,12 @@ end desc 'Runs CMake to prepare the project' task :configure => "../xgt-build" do - sh %( cmake -G Ninja -B ../xgt-build -S . -D CMAKE_BUILD_TYPE=RelWithDebInfo ) + sh %( cmake -G Ninja -B ../xgt-build -S . -D CMAKE_BUILD_TYPE=debug ) +end + +desc 'Runs CMake to prepare the project for testnet' +task :configure_testnet => "../xgt-build" do + sh %( cmake -G Ninja -B ../xgt-build -S . -D CMAKE_BUILD_TYPE=debug -D BUILD_XGT_TESTNET=ON ) end task :test do @@ -280,8 +295,8 @@ task :run do shared-file-size = 12G - p2p-endpoint = #{my_host}:#{2001 + instance_index} - webserver-http-endpoint = #{my_host}:#{8751 + instance_index * 2} + p2p-endpoint = #{my_host}:#{2001 + port_offset + instance_index} + webserver-http-endpoint = #{my_host}:#{8751 + port_offset + instance_index * 2} miner = ["#{wallet}","#{wif}"] mining-threads = #{mining_threads} @@ -291,13 +306,20 @@ task :run do enable-stale-production = #{mining_disabled? ? 'false' : 'true'} ))) - if seed_hosts && seed_hosts.any? + if from_genesis? + f.puts "p2p-seed-node = " + elsif seed_hosts && seed_hosts.any? f.puts "p2p-seed-node = #{seed_hosts.join(" ")}" end + f.puts "p2p-seed-node = " end $stderr.puts(File.read("#{data_dir}/config.ini")) - sh %(cd #{data_dir} && ../xgt-build/programs/xgtd/xgtd --data-dir=.) + flags = ['--data-dir=.'] + if from_genesis? + flags << '--from-genesis' + end + sh %(cd #{data_dir} && ../xgt-build/programs/xgtd/xgtd #{flags.join(' ')}) end desc 'Get approximate C++ LoC' @@ -305,237 +327,84 @@ task :wc do sh %(wc -l #{Dir.glob('**/*.{c,h}pp').join(' ')}) end -namespace :lazy_wallets do - task :name_test do - generate_keys = ->() { - master = Xgt::Ruby::Auth.random_wif - ks = { 'master' => master } - %w(recovery money social memo).each do |role| - private_key = Xgt::Ruby::Auth.generate_wif(wallet, master, 'recovery') - public_key = Xgt::Ruby::Auth.wif_to_public_key(private_key, address_prefix) - ks["#{role}_private"] = private_key - ks["#{role}_public"] = public_key - end - ks - } - - master = Xgt::Ruby::Auth.random_wif +def generate_keys + master = Xgt::Ruby::Auth.random_wif + ks = { 'master' => master } + %w(recovery money social memo).each do |role| private_key = Xgt::Ruby::Auth.generate_wif(wallet, master, 'recovery') public_key = Xgt::Ruby::Auth.wif_to_public_key(private_key, address_prefix) - - response = rpc.call('wallet_by_key_api.generate_wallet_name', { - 'recovery_keys' => [public_key] - }) - wallet_name = response['wallet_name'] - - txn = { - 'extensions' => [], - 'operations' => [ - { - 'type' => 'transfer_operation', - 'value' => { - 'amount' => { - 'amount' => '1', - 'precision' => 8, - 'nai' => '@@000000021' - }, - 'from' => 'XGT0000000000000000000000000000000000000000', - 'to' => wallet_name, - 'json_metadata' => '', - 'extensions' => [] - } - } - ] - } - - id = rpc.broadcast_transaction(txn, [wif], chain_id) - (puts 'Waiting...' or sleep 1) until rpc.transaction_ready?(id) - - keys = generate_keys.call - txn = { - 'extensions' => [], - 'operations' => [ - { - 'type' => 'wallet_update_operation', - 'value' => { - 'wallet' => wallet_name, - 'recovery' => { - 'weight_threshold' => 1, - 'account_auths' => [], - 'key_auths' => [[keys['recovery_public'], 1]] - }, - 'money' => { - 'weight_threshold' => 1, - 'account_auths' => [], - 'key_auths' => [[keys['money_public'], 1]] - }, - 'social' => { - 'weight_threshold' => 1, - 'account_auths' => [], - 'key_auths' => [[keys['social_public'], 1]] - }, - 'memo_key' => keys['memo_public'], - 'json_metadata' => '', - 'extensions' => [] - } - } - ] - } - - p txn - id = rpc.broadcast_transaction(txn, [private_key], chain_id) - (puts 'Waiting...' or sleep 1) until rpc.transaction_ready?(id) + ks["#{role}_private"] = private_key + ks["#{role}_public"] = public_key end -end - -namespace :catalyst do - generate_keys = ->() { - FileUtils.mkdir_p('out') - File.open('out/keys.json', 'w') do |f| - master = Xgt::Ruby::Auth.random_wif - ks = { 'master' => master } - %w(recovery money social memo witness).each do |role| - private_key = Xgt::Ruby::Auth.generate_wif(wallet, master, role) - public_key = Xgt::Ruby::Auth.wif_to_public_key(private_key, address_prefix) - ks["#{role}_private"] = private_key - ks["#{role}_public"] = public_key - end - response = rpc.call('wallet_by_key_api.generate_wallet_name', { - 'recovery_keys' => [ks['recovery_public']] - }) - ks['wallet_name'] = response['wallet_name'] - f.puts(JSON.pretty_generate(ks)) - end - } - keys = ->() { - JSON.load(File.open('out/keys.json')) - } + response = rpc.call('wallet_by_key_api.generate_wallet_name', { + 'recovery_keys' => [ks['recovery_public']] + }) + wallet_name = response['wallet_name'] + ks['wallet_name'] = wallet_name - does_witness_exist = ->() { - name = wallet_name.call - response = rpc.call('database_api.list_witnesses', { 'start' => name, 'limit' => 1, 'order' => 'by_name'}) || {} - witnesses = response['witnesses'] || [] - witness = witnesses.first || {} - (name == witness['owner']) - } - - desc 'Generate the keys for the witness' - task :generate_keys do - generate_keys.call - end - - desc 'Create a wallet for the witness' - task :create_wallet do - name = keys.call['wallet_name'] - - txn = { - 'extensions' => [], - 'operations' => [ - { - 'type' => 'wallet_create_operation', - 'value' => { - 'fee' => { - 'amount' => '0', - 'precision' => 8, - 'nai' => '@@000000021' - }, - 'creator' => wallet, - 'recovery' => { - 'weight_threshold' => 1, - 'account_auths' => [], - 'key_auths' => [[keys.call['recovery_public'], 1]] - }, - 'money' => { - 'weight_threshold' => 1, - 'account_auths' => [], - 'key_auths' => [[keys.call['money_public'], 1]] - }, - 'social' => { - 'weight_threshold' => 1, - 'account_auths' => [], - 'key_auths' => [[keys.call['social_public'], 1]] - }, - 'memo_key' => keys.call['memo_public'], - 'json_metadata' => '', - 'extensions' => [] - } - } - ] - } - - $stderr.puts(%(Creator is "#{wallet}" with wif "#{wif}"...)) - $stderr.puts(%(Creating wallet with master key "#{keys.call['master']}"...)) - signed = Xgt::Ruby::Auth.sign_transaction(rpc, txn, [wif], chain_id) - rpc.call('transaction_api.broadcast_transaction', [signed]) - end - - desc 'Register the witness' - task :register do - name = keys.call['wallet_name'] - - components = fee.split(' ') - decimal = BigDecimal(components.first) * 1 - final_fee = decimal.truncate.to_s + '.' + sprintf('%03d', (decimal.frac * 1000).truncate) + ' ' + components.last + ks +end - # raise 'Witness already registered!' if does_witness_exist.call +def create_wallet!(keys) + name = keys['wallet_name'] - txn = { - 'extensions' => [], - 'operations' => [{ - 'type' => 'witness_update_operation', + txn = { + 'extensions' => [], + 'operations' => [ + { + 'type' => 'wallet_create_operation', 'value' => { - 'owner' => name, - 'url' => 'http://witness-category/my-witness', - 'block_signing_key' => keys.call['witness_public'], - 'props' => { - 'account_creation_fee' => {'amount'=>'0','precision'=>8,'nai'=>'@@000000021'} + 'fee' => { + 'amount' => '0', + 'precision' => 8, + 'nai' => '@@000000021' + }, + 'creator' => wallet, + 'recovery' => { + 'weight_threshold' => 1, + 'account_auths' => [], + 'key_auths' => [[keys['recovery_public'], 1]] + }, + 'money' => { + 'weight_threshold' => 1, + 'account_auths' => [], + 'key_auths' => [[keys['money_public'], 1]] + }, + 'social' => { + 'weight_threshold' => 1, + 'account_auths' => [], + 'key_auths' => [[keys['social_public'], 1]] }, - 'fee' => {'amount'=>'0','precision'=>8,'nai'=>'@@000000021'} + 'memo_key' => keys['memo_public'], + 'json_metadata' => '', + 'extensions' => [] } - }] - } + } + ] + } + $stderr.puts(%(Creator is "#{wallet}" with wif "#{wif}"...)) + $stderr.puts(%(Creating wallet with master key "#{keys['master']}"...)) + signed = Xgt::Ruby::Auth.sign_transaction(rpc, txn, [wif], chain_id) + rpc.call('transaction_api.broadcast_transaction', [signed]) + name +end - signing_keys = keys.call['recovery_private'] - signed = Xgt::Ruby::Auth.sign_transaction(rpc, txn, [signing_keys], chain_id) - $stderr.puts(%(Registering witness with recovery private WIF "#{keys.call['recovery_private']}"...)) - $stderr.puts(%(Signing keypair is #{keys.call['witness_private']} (private) and #{keys.call['witness_public']} (public)...)) - response = rpc.call('transaction_api.broadcast_transaction', [signed]) - $stderr.puts(%(Registered witness #{name})) - end +namespace :machine do + src_dir = File.join(File.dirname(__FILE__), %(../xgtvm)) + dest_dir = File.join(File.dirname(__FILE__), %(libraries/vendor/xgtvm)) + dest_git_dir = File.join(dest_dir, '.git') - desc 'Assuming keys were generated, do everything else' - task :all => [:create_wallet, :register] - - desc 'Regenerate keys and do everything else' - task :really_all => [:generate_keys, :create_wallet, :register] -end - -namespace :contracts do - desc 'Generate a sample contract' - task :generate do - txn = { - 'extensions' => [], - 'operations' => [ - { - 'type' => 'contract_create_operation', - 'value' => { - 'owner' => wallet, - 'code' => "600260030100", - } - } - ] - } - signed = Xgt::Ruby::Auth.sign_transaction(rpc, txn, [wif], chain_id) - $stderr.puts(%(Registering contract... #{signed.to_json})) - response = rpc.call('transaction_api.broadcast_transaction', [signed]) - $stderr.puts(%(Received response contract... #{response})) + desc 'Remove machine-related files' + task :clean do + FileUtils.rm_r(dest_dir) if Dir.exist?(dest_dir) end - desc 'View sample contracts' - task :list do - response = rpc.call('contract_api.list_owner_contracts', { 'owner' => wallet }) || {} - p response + desc 'Vendor machine-related files' + task :vendor => [:clean] do + raise %(Directory #{src_dir} doesn't exist!) unless Dir.exist?(src_dir) + FileUtils.cp_r(src_dir, dest_dir) + FileUtils.rm_r(dest_git_dir) if File.exists?(dest_git_dir) end end diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index e4be93db..bcfabf20 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -1,4 +1,8 @@ -file(GLOB HEADERS "include/xgt/chain/*.hpp" "include/xgt/chain/util/*.hpp" "include/xgt/chain/xtt_objects/*.hpp") +file(GLOB HEADERS "include/xgt/chain/*.hpp" + "include/xgt/chain/util/*.hpp" + "include/xgt/chain/xtt_objects/*.hpp" + "include/keccak256.h" + ) ## SORT .cpp by most likely to change / break compile add_library( xgt_chain @@ -7,7 +11,7 @@ add_library( xgt_chain database.cpp index.cpp - machine.cpp + keccak256.c xtt_evaluator.cpp @@ -32,11 +36,14 @@ add_library( xgt_chain ${HEADERS} ) -target_link_libraries( xgt_chain xgt_protocol fc chainbase xgt_schema appbase mira +target_link_libraries( xgt_chain xgt_protocol fc chainbase xgt_schema appbase mira xgtvm ${PATCH_MERGE_LIB} ) target_include_directories( xgt_chain PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}" - PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_BINARY_DIR}/include" ) + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" + "${CMAKE_CURRENT_BINARY_DIR}/include" + "${CMAKE_CURRENT_SOURCE_DIR}/../vendor/xgtvm/libraries" + ) if( CLANG_TIDY_EXE ) set_target_properties( diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index eb1feb44..08b733b5 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -95,22 +95,6 @@ database::~database() clear_pending(); } -fc::sha256 bigint_to_hash(boost::multiprecision::uint256_t b) -{ - std::ostringstream os; - os << std::hex << std::setw(64) << std::setfill('0') << b; - std::string string_hash = os.str(); - return fc::sha256(string_hash); -} - -boost::multiprecision::uint256_t hash_to_bigint(fc::sha256 h) -{ - std::string prefix = "0x"; - std::string string_hash = h.str(); - std::string prepended_string_hash = prefix.append(string_hash); - return boost::multiprecision::uint256_t(prepended_string_hash); -} - #ifdef ENABLE_MIRA void set_index_helper( database& db, mira::index_type type, const boost::filesystem::path& p, const boost::any& cfg, std::vector< std::string > indices ) { @@ -600,6 +584,16 @@ void database::foreach_operation(std::function( boost::make_tuple( contract_hash, caller ) ); +} FC_CAPTURE_AND_RETHROW( (contract_hash)(caller) ) } + +const contract_storage_object* database::find_contract_storage( const contract_hash_type& contract_hash, const wallet_name_type& caller ) const +{ + return find< contract_storage_object, by_contract_and_caller >( boost::make_tuple( contract_hash, caller ) ); +} + const witness_object& database::get_witness( const wallet_name_type& name ) const { try { return get< witness_object, by_name >( name ); @@ -610,16 +604,46 @@ const witness_object* database::find_witness( const wallet_name_type& name ) con return find< witness_object, by_name >( name ); } +const contract_object& database::get_contract( const contract_hash_type& hash )const +{ try { + return get< contract_object, by_contract_hash >( hash ); +} FC_CAPTURE_AND_RETHROW( (hash) ) } + +const contract_object& database::get_contract_by_wallet( const wallet_name_type& wallet )const +{ try { + return get< contract_object, by_wallet >( wallet ); +} FC_CAPTURE_AND_RETHROW( (wallet) ) } + +const contract_object* database::find_contract( const contract_hash_type& hash )const +{ + return find< contract_object, by_contract_hash >( hash ); +} + +const contract_object* database::find_contract_by_wallet( const wallet_name_type& wallet )const +{ + return find< contract_object, by_wallet >( wallet ); +} + const wallet_object& database::get_account( const wallet_name_type& name )const { try { return get< wallet_object, by_name >( name ); } FC_CAPTURE_AND_RETHROW( (name) ) } +const wallet_object& database::get_account_by_en_address( const en_address_type& en_address )const +{ try { + return get< wallet_object, by_en_address >( en_address ); +} FC_CAPTURE_AND_RETHROW( (en_address) ) } + const wallet_object* database::find_account( const wallet_name_type& name )const { return find< wallet_object, by_name >( name ); } +const wallet_object* database::find_account_by_en_address( const en_address_type& en_address )const +{ + return find< wallet_object, by_en_address >( en_address ); +} + const comment_object& database::get_comment( const wallet_name_type& author, const shared_string& permlink )const { try { return get< comment_object, by_permlink >( boost::make_tuple( author, permlink ) ); @@ -652,13 +676,6 @@ const escrow_object* database::find_escrow( const wallet_name_type& name, uint32 return find< escrow_object, by_from_id >( boost::make_tuple( name, escrow_id ) ); } -/* -const contract_object& database::get_contract( const contract_hash_type& contract_hash )const -{ try { - return get< contract_object, by_contract_hash >( contract_hash ); -} FC_CAPTURE_AND_RETHROW( (contract_hash) ) } -*/ - const dynamic_global_property_object&database::get_dynamic_global_properties() const { try { return get< dynamic_global_property_object >(); @@ -1348,10 +1365,13 @@ void database::init_genesis( uint64_t init_supply ) create< wallet_object >( [&]( wallet_object& a ) { a.name = XGT_MINER_WALLET; + a.en_address = fc::ripemd160::hex_digest(XGT_MINER_WALLET); } ); + create< account_authority_object >( [&]( account_authority_object& auth ) { auth.account = XGT_MINER_WALLET; + auth.en_address = fc::ripemd160::hex_digest(XGT_MINER_WALLET); auth.recovery.weight_threshold = 1; auth.money.weight_threshold = 1; }); @@ -1359,6 +1379,7 @@ void database::init_genesis( uint64_t init_supply ) create< wallet_object >( [&]( wallet_object& a ) { a.name = XGT_INIT_MINER_NAME; + a.en_address = fc::ripemd160::hex_digest(XGT_INIT_MINER_NAME); a.memo_key = init_public_key; a.balance = asset( init_supply, XGT_SYMBOL ); } ); @@ -1366,6 +1387,7 @@ void database::init_genesis( uint64_t init_supply ) create< account_authority_object >( [&]( account_authority_object& auth ) { auth.account = XGT_INIT_MINER_NAME; + auth.en_address = fc::ripemd160::hex_digest(XGT_INIT_MINER_NAME); auth.recovery.add_authority( init_public_key, 1 ); auth.recovery.weight_threshold = 1; auth.money = auth.recovery; @@ -1381,10 +1403,13 @@ void database::init_genesis( uint64_t init_supply ) create< wallet_object >( [&]( wallet_object& a ) { a.name = XGT_NULL_WALLET; + a.en_address = fc::ripemd160::hex_digest(XGT_NULL_WALLET); } ); + create< account_authority_object >( [&]( account_authority_object& auth ) { auth.account = XGT_NULL_WALLET; + auth.en_address = fc::ripemd160::hex_digest(XGT_NULL_WALLET); auth.recovery.weight_threshold = 1; auth.money.weight_threshold = 1; }); @@ -1392,15 +1417,19 @@ void database::init_genesis( uint64_t init_supply ) create< wallet_object >( [&]( wallet_object& a ) { a.name = XGT_TREASURY_WALLET; + a.en_address = fc::ripemd160::hex_digest(XGT_TREASURY_WALLET); } ); create< wallet_object >( [&]( wallet_object& a ) { a.name = XGT_TEMP_WALLET; + a.en_address = fc::ripemd160::hex_digest(XGT_TEMP_WALLET); } ); + create< account_authority_object >( [&]( account_authority_object& auth ) { auth.account = XGT_TEMP_WALLET; + auth.en_address = fc::ripemd160::hex_digest(XGT_TEMP_WALLET); auth.recovery.weight_threshold = 0; auth.money.weight_threshold = 0; }); @@ -1420,6 +1449,7 @@ void database::init_genesis( uint64_t init_supply ) p.reverse_auction_seconds = XGT_REVERSE_AUCTION_WINDOW_SECONDS; p.next_maintenance_time = XGT_GENESIS_TIME; p.last_budget_time = XGT_GENESIS_TIME; + p.energy_multiplier = 1; } ); for( int i = 0; i < 0x10000; i++ ) diff --git a/libraries/chain/include/attributes.h b/libraries/chain/include/attributes.h new file mode 100644 index 00000000..f03aa255 --- /dev/null +++ b/libraries/chain/include/attributes.h @@ -0,0 +1,31 @@ +// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +// Copyright 2018 Pawel Bylica. +// Licensed under the Apache License, Version 2.0. + +#pragma once + +// Provide __has_attribute macro if not defined. +#ifndef __has_attribute +#define __has_attribute(name) 0 +#endif + +// Provide __has_builtin macro if not defined. +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +// [[always_inline]] +#if defined(_MSC_VER) +#define ALWAYS_INLINE __forceinline +#elif __has_attribute(always_inline) +#define ALWAYS_INLINE __attribute__((always_inline)) +#else +#define ALWAYS_INLINE +#endif + +// [[no_sanitize()]] +#if defined(__clang__) +#define NO_SANITIZE(sanitizer) __attribute__((no_sanitize(sanitizer))) +#else +#define NO_SANITIZE(sanitizer) +#endif diff --git a/libraries/chain/include/hash_types.h b/libraries/chain/include/hash_types.h new file mode 100644 index 00000000..caf6c288 --- /dev/null +++ b/libraries/chain/include/hash_types.h @@ -0,0 +1,41 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018-2019 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +union ethash_hash256 +{ + uint64_t word64s[4]; + uint32_t word32s[8]; + uint8_t bytes[32]; + char str[32]; +}; + +union ethash_hash512 +{ + uint64_t word64s[8]; + uint32_t word32s[16]; + uint8_t bytes[64]; + char str[64]; +}; + +union ethash_hash1024 +{ + union ethash_hash512 hash512s[2]; + uint64_t word64s[16]; + uint32_t word32s[32]; + uint8_t bytes[128]; + char str[128]; +}; + +#ifdef __cplusplus +} +#endif diff --git a/libraries/chain/include/keccak.h b/libraries/chain/include/keccak.h new file mode 100644 index 00000000..355b8dd2 --- /dev/null +++ b/libraries/chain/include/keccak.h @@ -0,0 +1,27 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018-2019 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. + */ + +#pragma once + +#include + +#include + +#ifndef __cplusplus +#define noexcept // Ignore noexcept in C code. +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +union ethash_hash256 ethash_keccak256(const uint8_t* data, size_t size); +union ethash_hash256 ethash_keccak256_32(const uint8_t data[32]); +union ethash_hash512 ethash_keccak512(const uint8_t* data, size_t size); +union ethash_hash512 ethash_keccak512_64(const uint8_t data[64]); + +#ifdef __cplusplus +} +#endif diff --git a/libraries/chain/include/keccak256.h b/libraries/chain/include/keccak256.h new file mode 100644 index 00000000..c09b5e02 --- /dev/null +++ b/libraries/chain/include/keccak256.h @@ -0,0 +1,54 @@ +/* sha3 - an implementation of Secure Hash Algorithm 3 (Keccak). + * based on the + * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011 + * by Guido Bertoni, Joan Daemen, Michaƫl Peeters and Gilles Van Assche + * + * Copyright: 2013 Aleksey Kravchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so. + * + * This program 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. Use this program at your own risk! + */ + +#ifndef __KECCAK256_H_ +#define __KECCAK256_H_ + +#include + +#define sha3_max_permutation_size 25 +#define sha3_max_rate_in_qwords 24 + +typedef struct SHA3_CTX { + /* 1600 bits algorithm hashing state */ + uint64_t hash[sha3_max_permutation_size]; + /* 1536-bit buffer for leftovers */ + uint64_t message[sha3_max_rate_in_qwords]; + /* count of bytes in the message[] buffer */ + uint16_t rest; + /* size of a message block processed at once */ + //unsigned block_size; +} SHA3_CTX; + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +void keccak_init(SHA3_CTX *ctx); +void keccak_update(SHA3_CTX *ctx, const unsigned char *msg, uint16_t size); +void keccak_final(SHA3_CTX *ctx, unsigned char* result); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __KECCAK256_H_ */ diff --git a/libraries/chain/include/rlpvalue/.gitignore b/libraries/chain/include/rlpvalue/.gitignore new file mode 100644 index 00000000..0203b4bb --- /dev/null +++ b/libraries/chain/include/rlpvalue/.gitignore @@ -0,0 +1,32 @@ +.deps/ +INSTALL +Makefile +Makefile.in +aclocal.m4 +autom4te.cache/ +compile +config.log +config.status +config.guess +config.sub +configure +depcomp +install-sh +missing +stamp-h1 +rlpvalue-config.h* +test-driver +libtool +ltmain.sh +test-suite.log + +*.a +*.la +*.lo +*.logs +*.o +*.pc +*.trs + +.dirstamp +.libs diff --git a/libraries/chain/include/rlpvalue/.gitmodules b/libraries/chain/include/rlpvalue/.gitmodules new file mode 100644 index 00000000..a740b3a7 --- /dev/null +++ b/libraries/chain/include/rlpvalue/.gitmodules @@ -0,0 +1,3 @@ +[submodule "univalue"] + path = univalue + url = https://github.com/jgarzik/univalue diff --git a/libraries/chain/include/rlpvalue/.travis.yml b/libraries/chain/include/rlpvalue/.travis.yml new file mode 100644 index 00000000..b5170879 --- /dev/null +++ b/libraries/chain/include/rlpvalue/.travis.yml @@ -0,0 +1,58 @@ +language: cpp + +compiler: + - clang + - gcc + +os: + - linux + - osx + +sudo: true + +env: + global: + - MAKEJOBS=-j3 + - RUN_TESTS=true + - BASE_OUTDIR=$TRAVIS_BUILD_DIR/out + +cache: + apt: true + +addons: + apt: + packages: + - pkg-config + +before_install: + - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; fi + +install: + - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew install gettext; fi + - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew install argp-standalone; fi + +before_script: + - if [ -n "$USE_SHELL" ]; then export CONFIG_SHELL="$USE_SHELL"; fi + - test -n "$USE_SHELL" && eval '"$USE_SHELL" -c "./autogen.sh"' || ./autogen.sh + +script: + - if [ -n "$RLPVALUE_CONFIG" ]; then unset CC; unset CXX; fi + - OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST + - RLPVALUE_CONFIG_ALL="--prefix=$TRAVIS_BUILD_DIR/depends/$HOST --bindir=$OUTDIR/bin --libdir=$OUTDIR/lib" + - ./configure --cache-file=config.cache $RLPVALUE_CONFIG_ALL $RLPVALUE_CONFIG || ( cat config.log && false) + - make -s $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL ; false ) + - export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib + - if [ "$RUN_TESTS" = "true" ]; then make $MAKEJOBS distcheck; fi + +#matrix: +# fast_finish: true +# include: +# - os: linux +# compiler: gcc +# env: RLPVALUE_CONFIG=--host=x86_64-w64-mingw32 RUN_TESTS=false +# addons: +# apt: +# packages: +# - g++-mingw-w64-x86-64 +# - gcc-mingw-w64-x86-64 +# - binutils-mingw-w64-x86-64 diff --git a/libraries/chain/include/rlpvalue/COPYING b/libraries/chain/include/rlpvalue/COPYING new file mode 100644 index 00000000..1fb429f3 --- /dev/null +++ b/libraries/chain/include/rlpvalue/COPYING @@ -0,0 +1,19 @@ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/libraries/chain/include/rlpvalue/Makefile.am b/libraries/chain/include/rlpvalue/Makefile.am new file mode 100644 index 00000000..f83246df --- /dev/null +++ b/libraries/chain/include/rlpvalue/Makefile.am @@ -0,0 +1,61 @@ +ACLOCAL_AMFLAGS = -I build-aux/m4 + +SUBDIRS = univalue + +UNIVALUE_CFLAGS = -I$(top_srcdir)/univalue/include + +include_HEADERS = include/rlpvalue.h +noinst_HEADERS = lib/rlpvalue_utffilter.h + +lib_LTLIBRARIES = librlpvalue.la + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = pc/librlpvalue.pc + +librlpvalue_la_SOURCES = \ + lib/rlpvalue.cpp \ + lib/rlpvalue_get.cpp \ + lib/rlpvalue_read.cpp \ + lib/rlpvalue_write.cpp + +librlpvalue_la_LDFLAGS = \ + -version-info $(LIBRLPVALUE_CURRENT):$(LIBRLPVALUE_REVISION):$(LIBRLPVALUE_AGE) \ + -no-undefined +librlpvalue_la_CXXFLAGS = -I$(top_srcdir)/include + +TESTS = test/object test/unitester + +noinst_PROGRAMS = src/rlp $(TESTS) + +src_rlp_SOURCES = \ + src/InfInt.h \ + src/tool.cpp \ + src/rlp2json.cpp \ + test/utilstrencodings.cpp +src_rlp_LDADD = librlpvalue.la univalue/.libs/libunivalue.a $(ARGP_LIBS) +src_rlp_CXXFLAGS = -I$(top_srcdir)/include $(UNIVALUE_CFLAGS) +src_rlp_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) + +TEST_DATA_DIR=test/data + +test_unitester_SOURCES = \ + src/rlp2json.cpp \ + test/unitester.cpp \ + test/utilstrencodings.h test/utilstrencodings.cpp +test_unitester_LDADD = librlpvalue.la univalue/.libs/libunivalue.a +test_unitester_CXXFLAGS = -I$(top_srcdir)/include $(UNIVALUE_CFLAGS) \ + -DJSON_TEST_SRC=\"$(srcdir)/$(TEST_DATA_DIR)\" +test_unitester_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) + +test_object_SOURCES = test/object.cpp +test_object_LDADD = librlpvalue.la +test_object_CXXFLAGS = -I$(top_srcdir)/include +test_object_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) + +TEST_FILES = \ + test/data/example.json \ + test/data/invalidRLPTest.json \ + test/data/longlist.json \ + test/data/rlptest.json + +EXTRA_DIST=$(TEST_FILES) diff --git a/libraries/chain/include/rlpvalue/README.md b/libraries/chain/include/rlpvalue/README.md new file mode 100644 index 00000000..8df996c1 --- /dev/null +++ b/libraries/chain/include/rlpvalue/README.md @@ -0,0 +1,22 @@ + +# RLPValue + +## Summary + +A universal value class for use with Ethereum RLP encoding/decoding. + +See https://github.com/ethereum/wiki/wiki/RLP for more. + +## Installation + +This project is a standard GNU +[autotools](https://www.gnu.org/software/automake/manual/html_node/Autotools-Introduction.html) +project. Build and install instructions are available in the `INSTALL` +file provided with GNU autotools. + +``` +$ ./autogen.sh +$ ./configure +$ make +``` + diff --git a/libraries/chain/include/rlpvalue/TODO.md b/libraries/chain/include/rlpvalue/TODO.md new file mode 100644 index 00000000..8e9b7dc0 --- /dev/null +++ b/libraries/chain/include/rlpvalue/TODO.md @@ -0,0 +1,21 @@ + +# TO-DO + +## Technical debt + +* univalue included as a git subtree because of difficulty in + installing dependencies across all travis test platforms. + Ideally: remove submodule, discover via configure. + +* win64 build disabled in travis due to lack of argp-standalone + on that platform. find argp-standalone, and re-enable win64. + +## Low priority + +Rearrange tree for easier 'git subtree' style use + +Namespace support - must come up with useful shorthand, avoiding +long Univalue::Univalue::Univalue usages forced upon library users. + +Improve test suite + diff --git a/libraries/chain/include/rlpvalue/a.out b/libraries/chain/include/rlpvalue/a.out new file mode 100755 index 00000000..1a3af65d Binary files /dev/null and b/libraries/chain/include/rlpvalue/a.out differ diff --git a/libraries/chain/include/rlpvalue/autogen.sh b/libraries/chain/include/rlpvalue/autogen.sh new file mode 100755 index 00000000..e02f905f --- /dev/null +++ b/libraries/chain/include/rlpvalue/autogen.sh @@ -0,0 +1,18 @@ +#!/bin/sh +# Copyright (c) 2013-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +set -e +srcdir="$(dirname $0)" +cd "$srcdir" +if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="`which glibtoolize 2>/dev/null`"; then + LIBTOOLIZE="${GLIBTOOLIZE}" + export LIBTOOLIZE +fi +which autoreconf >/dev/null || \ + (echo "configuration failed, please install autoconf first" && exit 1) +autoreconf --install --force --warnings=all + +cd univalue && ./autogen.sh + diff --git a/libraries/chain/include/rlpvalue/configure.ac b/libraries/chain/include/rlpvalue/configure.ac new file mode 100644 index 00000000..24737780 --- /dev/null +++ b/libraries/chain/include/rlpvalue/configure.ac @@ -0,0 +1,78 @@ +m4_define([librlpvalue_major_version], [1]) +m4_define([librlpvalue_minor_version], [1]) +m4_define([librlpvalue_micro_version], [4]) +m4_define([librlpvalue_interface_age], [4]) +# If you need a modifier for the version number. +# Normally empty, but can be used to make "fixup" releases. +m4_define([librlpvalue_extraversion], []) + +dnl libtool versioning from librlpvalue +m4_define([librlpvalue_current], [m4_eval(100 * librlpvalue_minor_version + librlpvalue_micro_version - librlpvalue_interface_age)]) +m4_define([librlpvalue_binary_age], [m4_eval(100 * librlpvalue_minor_version + librlpvalue_micro_version)]) +m4_define([librlpvalue_revision], [librlpvalue_interface_age]) +m4_define([librlpvalue_age], [m4_eval(librlpvalue_binary_age - librlpvalue_interface_age)]) +m4_define([librlpvalue_version], [librlpvalue_major_version().librlpvalue_minor_version().librlpvalue_micro_version()librlpvalue_extraversion()]) + + +AC_INIT([rlpvalue], [0.0.1], + [http://github.com/jgarzik/rlpvalue/]) + +dnl make the compilation flags quiet unless V=1 is used +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +AC_PREREQ(2.60) +AC_CONFIG_SRCDIR([lib/rlpvalue.cpp]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_MACRO_DIR([build-aux/m4]) +AC_CONFIG_HEADERS([rlpvalue-config.h]) +AX_SUBDIRS_CONFIGURE([univalue], [--disable-shared]) +AM_INIT_AUTOMAKE([subdir-objects foreign]) + +dnl Require C++11 compiler (no GNU extensions) +AC_PROG_CXX +AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory], [nodefault]) +AC_LANG(C++) + +LIBRLPVALUE_MAJOR_VERSION=librlpvalue_major_version +LIBRLPVALUE_MINOR_VERSION=librlpvalue_minor_version +LIBRLPVALUE_MICRO_VERSION=librlpvalue_micro_version +LIBRLPVALUE_INTERFACE_AGE=librlpvalue_interface_age + +# ABI version +# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html +LIBRLPVALUE_CURRENT=librlpvalue_current +LIBRLPVALUE_REVISION=librlpvalue_revision +LIBRLPVALUE_AGE=librlpvalue_age + +AC_CHECK_LIB(argp, argp_parse, ARGP_LIBS=-largp) +AC_SUBST(ARGP_LIBS) + +AC_SUBST(LIBRLPVALUE_CURRENT) +AC_SUBST(LIBRLPVALUE_REVISION) +AC_SUBST(LIBRLPVALUE_AGE) + +LT_INIT +LT_LANG([C++]) + +case $host in + *mingw*) + LIBTOOL_APP_LDFLAGS="$LIBTOOL_APP_LDFLAGS -all-static" + ;; +esac + +BUILD_EXEEXT= +case $build in + *mingw*) + BUILD_EXEEXT=".exe" + ;; +esac + +AC_CONFIG_FILES([ + Makefile + pc/librlpvalue.pc + pc/librlpvalue-uninstalled.pc]) + +AC_SUBST(LIBTOOL_APP_LDFLAGS) +AC_SUBST(BUILD_EXEEXT) +AC_OUTPUT + diff --git a/libraries/chain/include/rlpvalue/gen/gen.cpp b/libraries/chain/include/rlpvalue/gen/gen.cpp new file mode 100644 index 00000000..be3d4ccf --- /dev/null +++ b/libraries/chain/include/rlpvalue/gen/gen.cpp @@ -0,0 +1,82 @@ +// Copyright 2014 BitPay Inc. +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. + +// +// To re-create univalue_escapes.h: +// $ g++ -o gen gen.cpp +// $ ./gen > univalue_escapes.h +// + +#include +#include +#include "univalue.h" + +static bool initEscapes; +static std::string escapes[256]; + +static void initJsonEscape() +{ + // Escape all lower control characters (some get overridden with smaller sequences below) + for (int ch=0x00; ch<0x20; ++ch) { + char tmpbuf[20]; + snprintf(tmpbuf, sizeof(tmpbuf), "\\u%04x", ch); + escapes[ch] = std::string(tmpbuf); + } + + escapes[(int)'"'] = "\\\""; + escapes[(int)'\\'] = "\\\\"; + escapes[(int)'\b'] = "\\b"; + escapes[(int)'\f'] = "\\f"; + escapes[(int)'\n'] = "\\n"; + escapes[(int)'\r'] = "\\r"; + escapes[(int)'\t'] = "\\t"; + escapes[(int)'\x7f'] = "\\u007f"; // U+007F DELETE + + initEscapes = true; +} + +static void outputEscape() +{ + printf( "// Automatically generated file. Do not modify.\n" + "#ifndef BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n" + "#define BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n" + "static const char *escapes[256] = {\n"); + + for (unsigned int i = 0; i < 256; i++) { + if (escapes[i].empty()) { + printf("\tNULL,\n"); + } else { + printf("\t\""); + + unsigned int si; + for (si = 0; si < escapes[i].size(); si++) { + char ch = escapes[i][si]; + switch (ch) { + case '"': + printf("\\\""); + break; + case '\\': + printf("\\\\"); + break; + default: + printf("%c", escapes[i][si]); + break; + } + } + + printf("\",\n"); + } + } + + printf( "};\n" + "#endif // BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n"); +} + +int main (int argc, char *argv[]) +{ + initJsonEscape(); + outputEscape(); + return 0; +} + diff --git a/libraries/chain/include/rlpvalue/include/rlpvalue.h b/libraries/chain/include/rlpvalue/include/rlpvalue.h new file mode 100644 index 00000000..afebcd7d --- /dev/null +++ b/libraries/chain/include/rlpvalue/include/rlpvalue.h @@ -0,0 +1,126 @@ +// Copyright 2014 BitPay Inc. +// Copyright 2015 Bitcoin Core Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. + +#ifndef __RLPVALUE_H__ +#define __RLPVALUE_H__ + +#include +#include + +#include +#include +#include +#include + +#include // std::pair + +enum RLP_constants { + RLP_maxUintLen = 8, + RLP_bufferLenStart = 0x80, + RLP_listStart = 0xc0, +}; + +// really, a generic buffer, but we are in the global namespace, hence a prefix +class RLPBuffer { +public: + std::vector data; + + RLPBuffer() {} + RLPBuffer(const RLPBuffer& other) : data(other.data) {} + + void clear() { data.clear(); } + void reserve(size_t n) { data.reserve(n); } + void push_back(unsigned char ch) { data.push_back(ch); } + + std::vector::iterator begin() { return data.begin(); } + std::vector::iterator end() { return data.end(); } + + const unsigned char *get() const { return &data[0]; } + size_t size() const { return data.size(); } + std::string toStr() const { + std::string rs((const char *) &data[0], data.size()); + return rs; + } +}; + +// a single RLP value... which could be a nested list of RLP values +class RLPValue { +public: + enum VType { VARR, VBUF, }; + + RLPValue() { typ = VBUF; } + RLPValue(RLPValue::VType initialType) { + typ = initialType; + } + RLPValue(const std::string& val_) { + assign(val_); + } + RLPValue(const char *val_) { + std::string s(val_); + assign(s); + } + ~RLPValue() {} + + void clear(); + + void assign(const std::vector& val); + void assign(const std::string& val); + + bool setArray(); + + enum VType getType() const { return typ; } + std::string getValStr() const { return val.toStr(); } + bool empty() const { return (values.size() == 0); } + + size_t size() const { return values.size(); } + + const RLPValue& operator[](size_t index) const; + + bool isBuffer() const { return (typ == VBUF); } + bool isArray() const { return (typ == VARR); } + + bool push_back(const RLPValue& val); + bool push_back(const std::string& val_) { + RLPValue tmpVal; + tmpVal.assign(val_); + return push_back(tmpVal); + } + bool push_back(const char *val_) { + std::string s(val_); + return push_back(s); + } + bool push_backV(const std::vector& vec); + + std::string write() const; + + bool read(const unsigned char *raw, size_t len, + size_t& consumed, size_t& wanted); + +private: + bool readArray(const unsigned char *raw, size_t len, + size_t uintlen, size_t payloadlen, + size_t& consumed, size_t& wanted); + RLPValue::VType typ; + RLPBuffer val; + std::vector values; + + void writeBuffer(std::string& s) const; + void writeArray(std::string& s) const; + +public: + // Strict type-specific getters, these throw std::runtime_error if the + // value is of unexpected type + const std::vector& getValues() const; + std::string get_str() const; + const RLPValue& get_array() const; + + enum VType type() const { return getType(); } +}; + +extern const char *uvTypeName(RLPValue::VType t); + +extern const RLPValue NullRLPValue; + +#endif // __RLPVALUE_H__ diff --git a/libraries/chain/include/rlpvalue/lib/.gitignore b/libraries/chain/include/rlpvalue/lib/.gitignore new file mode 100644 index 00000000..ee7fc285 --- /dev/null +++ b/libraries/chain/include/rlpvalue/lib/.gitignore @@ -0,0 +1,2 @@ +gen +.libs diff --git a/libraries/chain/include/rlpvalue/lib/rlpvalue.cpp b/libraries/chain/include/rlpvalue/lib/rlpvalue.cpp new file mode 100644 index 00000000..6872f0e2 --- /dev/null +++ b/libraries/chain/include/rlpvalue/lib/rlpvalue.cpp @@ -0,0 +1,84 @@ +// Copyright 2014 BitPay Inc. +// Copyright 2015 Bitcoin Core Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include + +#include "../include/rlpvalue.h" + +const RLPValue NullRLPValue; + +void RLPValue::clear() +{ + typ = VBUF; + val.clear(); + values.clear(); +} + +void RLPValue::assign(const std::string& s) +{ + clear(); + + val.reserve(s.size()); + + for (auto it = s.begin(); it != s.end(); it++) { + val.push_back((unsigned char) *it); + } +} + +void RLPValue::assign(const std::vector& buf) +{ + val.data.assign(buf.begin(), buf.end()); +} + +bool RLPValue::setArray() +{ + clear(); + typ = VARR; + return true; +} + +bool RLPValue::push_back(const RLPValue& val_) +{ + if (typ != VARR) + return false; + + values.push_back(val_); + return true; +} + +bool RLPValue::push_backV(const std::vector& vec) +{ + if (typ != VARR) + return false; + + values.insert(values.end(), vec.begin(), vec.end()); + + return true; +} + +const RLPValue& RLPValue::operator[](size_t index) const +{ + if (typ != VARR) + return NullRLPValue; + if (index >= values.size()) + return NullRLPValue; + + return values.at(index); +} + +const char *uvTypeName(RLPValue::VType t) +{ + switch (t) { + case RLPValue::VARR: return "array"; + case RLPValue::VBUF: return "buffer"; + } + + // not reached + return NULL; +} + diff --git a/libraries/chain/include/rlpvalue/lib/rlpvalue_get.cpp b/libraries/chain/include/rlpvalue/lib/rlpvalue_get.cpp new file mode 100644 index 00000000..82fb663b --- /dev/null +++ b/libraries/chain/include/rlpvalue/lib/rlpvalue_get.cpp @@ -0,0 +1,38 @@ +// Copyright 2014 BitPay Inc. +// Copyright 2015 Bitcoin Core Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../include/rlpvalue.h" + +const std::vector& RLPValue::getValues() const +{ + if (typ != VARR) + throw std::runtime_error("JSON value is not an object or array as expected"); + return values; +} + +std::string RLPValue::get_str() const +{ + if (typ != VBUF) + throw std::runtime_error("JSON value is not a string as expected"); + return getValStr(); +} + +const RLPValue& RLPValue::get_array() const +{ + if (typ != VARR) + throw std::runtime_error("JSON value is not an array as expected"); + return *this; +} + diff --git a/libraries/chain/include/rlpvalue/lib/rlpvalue_read.cpp b/libraries/chain/include/rlpvalue/lib/rlpvalue_read.cpp new file mode 100644 index 00000000..5b317a28 --- /dev/null +++ b/libraries/chain/include/rlpvalue/lib/rlpvalue_read.cpp @@ -0,0 +1,216 @@ +// Copyright 2014 BitPay Inc. +// Copyright 2019 Bloq Inc. +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. + +#include +#include +#include "../include/rlpvalue.h" + +uint64_t toInteger(const unsigned char *raw, size_t len) +{ + if (len == 0) + return 0; + else if (len == 1) + return *raw; + else + return (raw[len - 1]) + (toInteger(raw, len - 1) * 256); +} + +bool RLPValue::readArray(const unsigned char *raw, size_t len, + size_t uintlen, size_t payloadlen, + size_t& consumed, size_t& wanted) +{ + const size_t prefixlen = 1; + + // validate list length, including possible addition overflows. + size_t expected = prefixlen + uintlen + payloadlen; + if ((expected > len) || (payloadlen > len)) { + wanted = expected > payloadlen ? expected : payloadlen; + return false; + } + + // we are type=array + if (!setArray()) + return false; + + size_t child_len = payloadlen; + size_t child_wanted = 0; + size_t total_consumed = 0; + + const unsigned char *list_ent = raw + prefixlen + uintlen; + + // recursively read until payloadlen bytes parsed, or error + while (child_len > 0) { + RLPValue childVal; + size_t child_consumed = 0; + + if (!childVal.read(list_ent, child_len, + child_consumed, child_wanted)) + return false; + + total_consumed += child_consumed; + list_ent += child_consumed; + child_len -= child_consumed; + + values.push_back(childVal); + } + + consumed = total_consumed; + return true; +} + +bool RLPValue::read(const unsigned char *raw, size_t len, + size_t& consumed, size_t& wanted) +{ + clear(); + consumed = 0; + wanted = 0; + + std::vector stack; + std::vector buf; + const unsigned char* end = raw + len; + + const size_t prefixlen = 1; + + unsigned char ch = *raw; + + if (len < 1) { + wanted = 1; + goto out_fail; + } + + // Case 1: [prefix is 1-byte data buffer] + if (ch <= 0x7f) { + const unsigned char *tok_start = raw; + const unsigned char *tok_end = tok_start + prefixlen; + assert(tok_end <= end); + + // parsing done; assign data buffer value. + buf.assign(tok_start, tok_end); + assign(buf); + + consumed = buf.size(); + + // Case 2: [prefix, including buffer length][data] + } else if ((ch >= 0x80) && (ch <= 0xb7)) { + size_t blen = ch - 0x80; + size_t expected = prefixlen + blen; + + if (len < expected) { + wanted = expected; + goto out_fail; + } + + const unsigned char *tok_start = raw + 1; + const unsigned char *tok_end = tok_start + blen; + assert(tok_end <= end); + + // require minimal encoding + if ((blen == 1) && (tok_start[0] <= 0x7f)) + goto out_fail; + + // parsing done; assign data buffer value. + buf.assign(tok_start, tok_end); + assign(buf); + + consumed = expected; + + // Case 3: [prefix][buffer length][data] + } else if ((ch >= 0xb8) && (ch <= 0xbf)) { + size_t uintlen = ch - 0xb7; + size_t expected = prefixlen + uintlen; + + if (len < expected) { + wanted = expected; + goto out_fail; + } + + assert(uintlen > 0 && uintlen <= RLP_maxUintLen); + + const unsigned char *tok_start = raw + prefixlen; + if ((uintlen > 1) && (tok_start[0] == 0)) // no leading zeroes + goto out_fail; + + // read buffer length + uint64_t slen = toInteger(tok_start, uintlen); + + // validate buffer length, including possible addition overflows. + expected = prefixlen + uintlen + slen; + if ((slen < (RLP_listStart - RLP_bufferLenStart - RLP_maxUintLen)) || + (expected > len) || (slen > len)) { + wanted = slen > expected ? slen : expected; + goto out_fail; + } + + // parsing done; assign data buffer value. + tok_start = raw + prefixlen + uintlen; + const unsigned char *tok_end = tok_start + slen; + buf.assign(tok_start, tok_end); + assign(buf); + + consumed = expected; + + // Case 4: [prefix][list] + } else if ((ch >= 0xc0) && (ch <= 0xf7)) { + size_t payloadlen = ch - 0xc0; + size_t expected = prefixlen + payloadlen; + size_t list_consumed = 0; + size_t list_wanted = 0; + + // read list payload + if (!readArray(raw, len, 0, payloadlen, list_consumed, list_wanted)) { + wanted = list_wanted; + goto out_fail; + } + + assert(list_consumed == payloadlen); + + consumed = expected; + + // Case 5: [prefix][list length][list] + } else { + assert((ch >= 0xf8) && (ch <= 0xff)); + + size_t uintlen = ch - 0xf7; + size_t expected = prefixlen + uintlen; + + if (len < expected) { + wanted = expected; + goto out_fail; + } + + assert(uintlen > 0 && uintlen <= RLP_maxUintLen); + + const unsigned char *tok_start = raw + prefixlen; + if ((uintlen > 1) && (tok_start[0] == 0)) // no leading zeroes + goto out_fail; + + // read list length + size_t payloadlen = toInteger(tok_start, uintlen); + + // special requirement for non-immediate length + if (payloadlen < (0x100 - RLP_listStart - RLP_maxUintLen)) + goto out_fail; + + size_t list_consumed = 0; + size_t list_wanted = 0; + + // read list payload + if (!readArray(raw, len, uintlen, payloadlen, list_consumed, list_wanted)) { + wanted = list_wanted; + goto out_fail; + } + + assert(list_consumed == payloadlen); + + consumed = prefixlen + uintlen + payloadlen; + } + + return true; + +out_fail: + clear(); + return false; +} + diff --git a/libraries/chain/include/rlpvalue/lib/rlpvalue_utffilter.h b/libraries/chain/include/rlpvalue/lib/rlpvalue_utffilter.h new file mode 100644 index 00000000..da1bde02 --- /dev/null +++ b/libraries/chain/include/rlpvalue/lib/rlpvalue_utffilter.h @@ -0,0 +1,119 @@ +// Copyright 2016 Wladimir J. van der Laan +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. +#ifndef RLPVALUE_UTFFILTER_H +#define RLPVALUE_UTFFILTER_H + +#include + +/** + * Filter that generates and validates UTF-8, as well as collates UTF-16 + * surrogate pairs as specified in RFC4627. + */ +class JSONUTF8StringFilter +{ +public: + explicit JSONUTF8StringFilter(std::string &s): + str(s), is_valid(true), codepoint(0), state(0), surpair(0) + { + } + // Write single 8-bit char (may be part of UTF-8 sequence) + void push_back(unsigned char ch) + { + if (state == 0) { + if (ch < 0x80) // 7-bit ASCII, fast direct pass-through + str.push_back(ch); + else if (ch < 0xc0) // Mid-sequence character, invalid in this state + is_valid = false; + else if (ch < 0xe0) { // Start of 2-byte sequence + codepoint = (ch & 0x1f) << 6; + state = 6; + } else if (ch < 0xf0) { // Start of 3-byte sequence + codepoint = (ch & 0x0f) << 12; + state = 12; + } else if (ch < 0xf8) { // Start of 4-byte sequence + codepoint = (ch & 0x07) << 18; + state = 18; + } else // Reserved, invalid + is_valid = false; + } else { + if ((ch & 0xc0) != 0x80) // Not a continuation, invalid + is_valid = false; + state -= 6; + codepoint |= (ch & 0x3f) << state; + if (state == 0) + push_back_u(codepoint); + } + } + // Write codepoint directly, possibly collating surrogate pairs + void push_back_u(unsigned int codepoint_) + { + if (state) // Only accept full codepoints in open state + is_valid = false; + if (codepoint_ >= 0xD800 && codepoint_ < 0xDC00) { // First half of surrogate pair + if (surpair) // Two subsequent surrogate pair openers - fail + is_valid = false; + else + surpair = codepoint_; + } else if (codepoint_ >= 0xDC00 && codepoint_ < 0xE000) { // Second half of surrogate pair + if (surpair) { // Open surrogate pair, expect second half + // Compute code point from UTF-16 surrogate pair + append_codepoint(0x10000 | ((surpair - 0xD800)<<10) | (codepoint_ - 0xDC00)); + surpair = 0; + } else // Second half doesn't follow a first half - fail + is_valid = false; + } else { + if (surpair) // First half of surrogate pair not followed by second - fail + is_valid = false; + else + append_codepoint(codepoint_); + } + } + // Check that we're in a state where the string can be ended + // No open sequences, no open surrogate pairs, etc + bool finalize() + { + if (state || surpair) + is_valid = false; + return is_valid; + } +private: + std::string &str; + bool is_valid; + // Current UTF-8 decoding state + unsigned int codepoint; + int state; // Top bit to be filled in for next UTF-8 byte, or 0 + + // Keep track of the following state to handle the following section of + // RFC4627: + // + // To escape an extended character that is not in the Basic Multilingual + // Plane, the character is represented as a twelve-character sequence, + // encoding the UTF-16 surrogate pair. So, for example, a string + // containing only the G clef character (U+1D11E) may be represented as + // "\uD834\uDD1E". + // + // Two subsequent \u.... may have to be replaced with one actual codepoint. + unsigned int surpair; // First half of open UTF-16 surrogate pair, or 0 + + void append_codepoint(unsigned int codepoint_) + { + if (codepoint_ <= 0x7f) + str.push_back((char)codepoint_); + else if (codepoint_ <= 0x7FF) { + str.push_back((char)(0xC0 | (codepoint_ >> 6))); + str.push_back((char)(0x80 | (codepoint_ & 0x3F))); + } else if (codepoint_ <= 0xFFFF) { + str.push_back((char)(0xE0 | (codepoint_ >> 12))); + str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F))); + str.push_back((char)(0x80 | (codepoint_ & 0x3F))); + } else if (codepoint_ <= 0x1FFFFF) { + str.push_back((char)(0xF0 | (codepoint_ >> 18))); + str.push_back((char)(0x80 | ((codepoint_ >> 12) & 0x3F))); + str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F))); + str.push_back((char)(0x80 | (codepoint_ & 0x3F))); + } + } +}; + +#endif diff --git a/libraries/chain/include/rlpvalue/lib/rlpvalue_write.cpp b/libraries/chain/include/rlpvalue/lib/rlpvalue_write.cpp new file mode 100644 index 00000000..53449ecd --- /dev/null +++ b/libraries/chain/include/rlpvalue/lib/rlpvalue_write.cpp @@ -0,0 +1,83 @@ +// Copyright 2014 BitPay Inc. +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. + +#include +#include +#include "../include/rlpvalue.h" + +std::string RLPValue::write() const +{ + std::string s; + + switch (typ) { + case VARR: + writeArray(s); + break; + case VBUF: + writeBuffer(s); + break; + } + + return s; +} + +std::string encodeBinary(uint64_t n) +{ + std::string rs; + + if (n == 0) { + // do nothing; return empty string + } else { + rs.assign(encodeBinary(n / 256)); + + unsigned char ch = n % 256; + rs.append((const char *) &ch, 1); + } + + return rs; +} + +static std::string encodeLength(size_t n, unsigned char offset) +{ + std::string rs; + + if (n < 56) { + unsigned char ch = n + offset; + rs.assign((const char *) &ch, 1); + } + + else { + // assert(n too big); + std::string binlen = encodeBinary(n); + + unsigned char ch = binlen.size() + offset + 55; + rs.assign((const char *) &ch, 1); + rs.append(binlen); + } + + return rs; +} + +void RLPValue::writeBuffer(std::string& s) const +{ + const unsigned char *p = val.size() ? val.get() : nullptr; + size_t sz = val.size(); + + if ((sz == 1) && (p[0] < 0x80)) + s.append((const char *) p, 1); + else + s += encodeLength(sz, 0x80) + val.toStr(); +} + +void RLPValue::writeArray(std::string& s) const +{ + std::string tmp; + for (auto it = values.begin(); it != values.end(); it++) { + const RLPValue& val = *it; + tmp += val.write(); + } + + s += encodeLength(tmp.size(), 0xC0) + tmp; +} + diff --git a/libraries/chain/include/rlpvalue/main.cpp b/libraries/chain/include/rlpvalue/main.cpp new file mode 100644 index 00000000..11427efb --- /dev/null +++ b/libraries/chain/include/rlpvalue/main.cpp @@ -0,0 +1,48 @@ +#include "include/rlpvalue.h" +#include "lib/rlpvalue.cpp" +#include "lib/rlpvalue_get.cpp" +#include "lib/rlpvalue_write.cpp" +#include "test/utilstrencodings.cpp" +#include + +int main() { + std::string dogIns = "dog"; + std::string dogOuts = "83646f67"; + + // Parse input string + RLPValue dogV = RLPValue(dogIns); + + // Parse expected output, print corresponding input -- note that 0x has been stripped from hex output + std::vector outb = ParseHex(dogOuts); + std::string outbStr(outb.begin(), outb.end()); + + std::cout << "83646f67 to c_str:" << std::endl; + std::cout << outbStr << std::endl; + + // Generate output rlp-encoded hex + std::string dogGenOutput = dogV.write(); + std::string dogGenHex = HexStr( dogGenOutput.begin(), dogGenOutput.end() ); + + // Inspect type of RLP value -- buffer/array + std::cout << "\nRLPValue type: " << std::endl; + std::cout << uvTypeName( dogV.type() ) << "\n\n" << std::endl; + + + + std::string catIns = "cat"; + std::string catOuts = "83636174"; + + RLPValue catV = RLPValue(catIns); + + // Generate output rlp-encoded hex + std::string catGenOutput = catV.write(); + std::string catGenHex = HexStr( catGenOutput.begin(), catGenOutput.end() ); + + std::cout << "Cat to RLP:" << std::endl; + std::cout << catGenHex.c_str() << std::endl; + + std::cout << "\nRLPValue type: " << std::endl; + std::cout << uvTypeName( dogV.type() ) << std::endl; + + return 0; +} diff --git a/libraries/chain/include/rlpvalue/pc/librlpvalue-uninstalled.pc.in b/libraries/chain/include/rlpvalue/pc/librlpvalue-uninstalled.pc.in new file mode 100644 index 00000000..484bccfc --- /dev/null +++ b/libraries/chain/include/rlpvalue/pc/librlpvalue-uninstalled.pc.in @@ -0,0 +1,9 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: librlpvalue +Description: librlpvalue, C++ universal value object and JSON library +Version: @VERSION@ +Libs: ${pc_top_builddir}/${pcfiledir}/librlpvalue.la diff --git a/libraries/chain/include/rlpvalue/pc/librlpvalue.pc.in b/libraries/chain/include/rlpvalue/pc/librlpvalue.pc.in new file mode 100644 index 00000000..faf5e647 --- /dev/null +++ b/libraries/chain/include/rlpvalue/pc/librlpvalue.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: librlpvalue +Description: librlpvalue, C++ universal value object and JSON library +Version: @VERSION@ +Libs: -L${libdir} -lrlpvalue +Cflags: -I${includedir} diff --git a/libraries/chain/include/rlpvalue/src/.gitignore b/libraries/chain/include/rlpvalue/src/.gitignore new file mode 100644 index 00000000..771e1508 --- /dev/null +++ b/libraries/chain/include/rlpvalue/src/.gitignore @@ -0,0 +1,3 @@ + +rlp + diff --git a/libraries/chain/include/rlpvalue/src/InfInt.h b/libraries/chain/include/rlpvalue/src/InfInt.h new file mode 100644 index 00000000..14ff2158 --- /dev/null +++ b/libraries/chain/include/rlpvalue/src/InfInt.h @@ -0,0 +1,1371 @@ +/* + * InfInt - Arbitrary-Precision Integer Arithmetic Library + * Copyright (C) 2013 Sercan Tutar + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * + * USAGE: + * It is pretty straight forward to use the library. Just create an instance of + * InfInt class and start using it. + * + * Useful methods: + * intSqrt: integer square root operation + * digitAt: returns digit at index + * numberOfDigits: returns number of digits + * size: returns size in bytes + * toString: converts it to a string + * + * There are also conversion methods which allow conversion to primitive types: + * toInt, toLong, toLongLong, toUnsignedInt, toUnsignedLong, toUnsignedLongLong. + * + * You may define INFINT_USE_EXCEPTIONS and library methods will start raising + * InfIntException in case of error instead of writing error messages using + * std::cerr. + * + * See ReadMe.txt for more info. + * + * + * No overflows, happy programmers! + * + */ + +#ifndef INFINT_H_ +#define INFINT_H_ + +#include +#include +#include +#include +#include + +//#include +//#include + +#ifndef LONG_LONG_MIN +#define LONG_LONG_MIN std::numeric_limits::min() +#define LONG_LONG_MAX std::numeric_limits::max() +#define ULONG_LONG_MAX std::numeric_limits::max() +#endif + +#ifdef INFINT_USE_EXCEPTIONS +#include +#endif + +typedef int ELEM_TYPE; +typedef long long PRODUCT_TYPE; +static const ELEM_TYPE BASE = 1000000000; +static const ELEM_TYPE UPPER_BOUND = 999999999; +static const ELEM_TYPE DIGIT_COUNT = 9; +static const int powersOfTen[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 }; + +#ifdef INFINT_USE_EXCEPTIONS +class InfIntException: public std::exception +{ +public: + InfIntException(const std::string& txt) throw (); + ~InfIntException() throw (); + const char* what() const throw (); +private: + std::string txt; +}; + +inline InfIntException::InfIntException(const std::string& txt) throw () : +std::exception(), txt(txt) +{ +} + +inline InfIntException::~InfIntException() throw () +{ +} + +inline const char* InfIntException::what() const throw () +{ + return txt.c_str(); +} +#endif + +inline static div_t my_div(int num, int denom) +{ + div_t result; + result.quot = num / denom; + result.rem = num - denom * result.quot; + return result; +} + +inline static ldiv_t my_ldiv(long num, long denom) +{ + ldiv_t result; + result.quot = num / denom; + result.rem = num - denom * result.quot; + return result; +} + +inline static lldiv_t my_lldiv(long long num, long long denom) +{ + lldiv_t result; + result.quot = num / denom; + result.rem = num - denom * result.quot; + return result; +} + +class InfInt +{ + friend std::ostream& operator<<(std::ostream &s, const InfInt &n); + friend std::istream& operator>>(std::istream &s, InfInt &val); + +public: + /* constructors */ + InfInt(); + InfInt(const char* c); + InfInt(const std::string& s); + InfInt(int l); + InfInt(long l); + InfInt(long long l); + InfInt(unsigned int l); + InfInt(unsigned long l); + InfInt(unsigned long long l); + InfInt(const InfInt& l); + + /* assignment operators */ + const InfInt& operator=(const char* c); + const InfInt& operator=(const std::string& s); + const InfInt& operator=(int l); + const InfInt& operator=(long l); + const InfInt& operator=(long long l); + const InfInt& operator=(unsigned int l); + const InfInt& operator=(unsigned long l); + const InfInt& operator=(unsigned long long l); + const InfInt& operator=(const InfInt& l); + + /* unary increment/decrement operators */ + const InfInt& operator++(); + const InfInt& operator--(); + InfInt operator++(int); + InfInt operator--(int); + + /* operational assignments */ + const InfInt& operator+=(const InfInt& rhs); + const InfInt& operator-=(const InfInt& rhs); + const InfInt& operator*=(const InfInt& rhs); + const InfInt& operator/=(const InfInt& rhs); // throw + const InfInt& operator%=(const InfInt& rhs); // throw + const InfInt& operator*=(ELEM_TYPE rhs); + + /* operations */ + InfInt operator-() const; + InfInt operator+(const InfInt& rhs) const; + InfInt operator-(const InfInt& rhs) const; + InfInt operator*(const InfInt& rhs) const; + InfInt operator/(const InfInt& rhs) const; // throw + InfInt operator%(const InfInt& rhs) const; // throw + InfInt operator*(ELEM_TYPE rhs) const; + + /* relational operations */ + bool operator==(const InfInt& rhs) const; + bool operator!=(const InfInt& rhs) const; + bool operator<(const InfInt& rhs) const; + bool operator<=(const InfInt& rhs) const; + bool operator>(const InfInt& rhs) const; + bool operator>=(const InfInt& rhs) const; + + /* integer square root */ + InfInt intSqrt() const; // throw + + /* digit operations */ + char digitAt(size_t i) const; // throw + size_t numberOfDigits() const; + + /* size in bytes */ + size_t size() const; + + /* string conversion */ + std::string toString() const; + + /* conversion to primitive types */ + int toInt() const; // throw + long toLong() const; // throw + long long toLongLong() const; // throw + unsigned int toUnsignedInt() const; // throw + unsigned long toUnsignedLong() const; // throw + unsigned long long toUnsignedLongLong() const; // throw + +private: + static ELEM_TYPE dInR(const InfInt& R, const InfInt& D); + static void multiplyByDigit(ELEM_TYPE factor, std::vector& val); + + void correct(bool justCheckLeadingZeros = false, bool hasValidSign = false); + void fromString(const std::string& s); + void optimizeSqrtSearchBounds(InfInt& lo, InfInt& hi) const; + void truncateToBase(); + bool equalizeSigns(); + void removeLeadingZeros(); + + std::vector val; // number with base FACTOR + bool pos; // true if number is positive +}; + +inline InfInt::InfInt() : pos(true) +{ + //PROFINY_SCOPE + val.push_back((ELEM_TYPE) 0); +} + +inline InfInt::InfInt(const char* c) +{ + //PROFINY_SCOPE + fromString(c); +} + +inline InfInt::InfInt(const std::string& s) +{ + //PROFINY_SCOPE + fromString(s); +} + +inline InfInt::InfInt(int l) : pos(l >= 0) +{ + //PROFINY_SCOPE + bool subtractOne = false; + if (l == INT_MIN) + { + subtractOne = true; + ++l; + } + + if (!pos) + { + l = -l; + } + do + { + div_t dt = my_div(l, BASE); + val.push_back((ELEM_TYPE) dt.rem); + l = dt.quot; + } while (l > 0); + + if (subtractOne) + { + --*this; + } +} + +inline InfInt::InfInt(long l) : pos(l >= 0) +{ + //PROFINY_SCOPE + bool subtractOne = false; + if (l == LONG_MIN) + { + subtractOne = true; + ++l; + } + + if (!pos) + { + l = -l; + } + do + { + ldiv_t dt = my_ldiv(l, BASE); + val.push_back((ELEM_TYPE) dt.rem); + l = dt.quot; + } while (l > 0); + + if (subtractOne) + { + --*this; + } +} + +inline InfInt::InfInt(long long l) : pos(l >= 0) +{ + //PROFINY_SCOPE + bool subtractOne = false; + if (l == LONG_LONG_MIN) + { + subtractOne = true; + ++l; + } + + if (!pos) + { + l = -l; + } + do + { + lldiv_t dt = my_lldiv(l, BASE); + val.push_back((ELEM_TYPE) dt.rem); + l = dt.quot; + } while (l > 0); + + if (subtractOne) + { + --*this; + } +} + +inline InfInt::InfInt(unsigned int l) : pos(true) +{ + //PROFINY_SCOPE + do + { + val.push_back((ELEM_TYPE) (l % BASE)); + l = l / BASE; + } while (l > 0); +} + +inline InfInt::InfInt(unsigned long l) : pos(true) +{ + //PROFINY_SCOPE + do + { + val.push_back((ELEM_TYPE) (l % BASE)); + l = l / BASE; + } while (l > 0); +} + +inline InfInt::InfInt(unsigned long long l) : pos(true) +{ + //PROFINY_SCOPE + do + { + val.push_back((ELEM_TYPE) (l % BASE)); + l = l / BASE; + } while (l > 0); +} + +inline InfInt::InfInt(const InfInt& l) : val(l.val), pos(l.pos) +{ + //PROFINY_SCOPE +} + +inline const InfInt& InfInt::operator=(const char* c) +{ + //PROFINY_SCOPE + fromString(c); + return *this; +} + +inline const InfInt& InfInt::operator=(const std::string& s) +{ + //PROFINY_SCOPE + fromString(s); + return *this; +} + +inline const InfInt& InfInt::operator=(int l) +{ + //PROFINY_SCOPE + bool subtractOne = false; + if (l == INT_MIN) + { + subtractOne = true; + ++l; + } + + pos = l >= 0; + val.clear(); + if (!pos) + { + l = -l; + } + do + { + div_t dt = my_div(l, BASE); + val.push_back((ELEM_TYPE) dt.rem); + l = dt.quot; + } while (l > 0); + + return subtractOne ? --*this : *this; +} + +inline const InfInt& InfInt::operator=(long l) +{ + //PROFINY_SCOPE + bool subtractOne = false; + if (l == LONG_MIN) + { + subtractOne = true; + ++l; + } + + pos = l >= 0; + val.clear(); + if (!pos) + { + l = -l; + } + do + { + ldiv_t dt = my_ldiv(l, BASE); + val.push_back((ELEM_TYPE) dt.rem); + l = dt.quot; + } while (l > 0); + + return subtractOne ? --*this : *this; +} + +inline const InfInt& InfInt::operator=(long long l) +{ + //PROFINY_SCOPE + bool subtractOne = false; + if (l == LONG_LONG_MIN) + { + subtractOne = true; + ++l; + } + + pos = l >= 0; + val.clear(); + if (!pos) + { + l = -l; + } + do + { + lldiv_t dt = my_lldiv(l, BASE); + val.push_back((ELEM_TYPE) dt.rem); + l = dt.quot; + } while (l > 0); + + return subtractOne ? --*this : *this; +} + +inline const InfInt& InfInt::operator=(unsigned int l) +{ + //PROFINY_SCOPE + pos = true; + val.clear(); + do + { + val.push_back((ELEM_TYPE) (l % BASE)); + l = l / BASE; + } while (l > 0); + return *this; +} + +inline const InfInt& InfInt::operator=(unsigned long l) +{ + //PROFINY_SCOPE + pos = true; + val.clear(); + do + { + val.push_back((ELEM_TYPE) (l % BASE)); + l = l / BASE; + } while (l > 0); + return *this; +} + +inline const InfInt& InfInt::operator=(unsigned long long l) +{ + //PROFINY_SCOPE + pos = true; + val.clear(); + do + { + val.push_back((ELEM_TYPE) (l % BASE)); + l = l / BASE; + } while (l > 0); + return *this; +} + +inline const InfInt& InfInt::operator=(const InfInt& l) +{ + //PROFINY_SCOPE + pos = l.pos; + val = l.val; + return *this; +} + +inline const InfInt& InfInt::operator++() +{ + //PROFINY_SCOPE + val[0] += (pos ? 1 : -1); + this->correct(false, true); + return *this; +} + +inline const InfInt& InfInt::operator--() +{ + //PROFINY_SCOPE + val[0] -= (pos ? 1 : -1); + this->correct(false, true); + return *this; +} + +inline InfInt InfInt::operator++(int) +{ + //PROFINY_SCOPE + InfInt result = *this; + val[0] += (pos ? 1 : -1); + this->correct(false, true); + return result; +} + +inline InfInt InfInt::operator--(int) +{ + //PROFINY_SCOPE + InfInt result = *this; + val[0] -= (pos ? 1 : -1); + this->correct(false, true); + return result; +} + +inline const InfInt& InfInt::operator+=(const InfInt& rhs) +{ + //PROFINY_SCOPE + if (rhs.val.size() > val.size()) + { + val.resize(rhs.val.size(), 0); + } + for (size_t i = 0; i < val.size(); ++i) + { + val[i] = (pos ? val[i] : -val[i]) + (i < rhs.val.size() ? (rhs.pos ? rhs.val[i] : -rhs.val[i]) : 0); + } + correct(); + return *this; +} + +inline const InfInt& InfInt::operator-=(const InfInt& rhs) +{ + //PROFINY_SCOPE + if (rhs.val.size() > val.size()) + { + val.resize(rhs.val.size(), 0); + } + for (size_t i = 0; i < val.size(); ++i) + { + val[i] = (pos ? val[i] : -val[i]) - (i < rhs.val.size() ? (rhs.pos ? rhs.val[i] : -rhs.val[i]) : 0); + } + correct(); + return *this; +} + +inline const InfInt& InfInt::operator*=(const InfInt& rhs) +{ + //PROFINY_SCOPE + // TODO: optimize (do not use operator*) + *this = *this * rhs; + return *this; +} + +inline const InfInt& InfInt::operator/=(const InfInt& rhs) +{ + //PROFINY_SCOPE + if (rhs == 0) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("division by zero"); +#else + std::cerr << "Division by zero!" << std::endl; + return *this; +#endif + } + InfInt R, D = (rhs.pos ? rhs : -rhs), N = (pos ? *this : -*this); + bool oldpos = pos; + std::fill(val.begin(), val.end(), 0); + for (int i = (int) N.val.size() - 1; i >= 0; --i) + { + R.val.insert(R.val.begin(), N.val[i]); + R.correct(true); + ELEM_TYPE cnt = dInR(R, D); + R -= D * cnt; + val[i] += cnt; + } + correct(); + pos = (val.size() == 1 && val[0] == 0) ? true : (oldpos == rhs.pos); + return *this; +} + +inline const InfInt& InfInt::operator%=(const InfInt& rhs) +{ + //PROFINY_SCOPE + // TODO: optimize (do not use operator%) + *this = *this % rhs; + return *this; +// if (rhs == 0) +// { +//#ifdef INFINT_USE_EXCEPTIONS +// throw InfIntException("division by zero"); +//#else +// std::cerr << "Division by zero!" << std::endl; +// return *this; +//#endif +// } +// InfInt D = (rhs.pos ? rhs : -rhs), N = (pos ? *this : -*this); +// bool oldpos = pos; +// val.clear(); +// for (int i = (int) N.val.size() - 1; i >= 0; --i) +// { +// val.insert(val.begin(), N.val[i]); +// correct(true); +// *this -= D * dInR(*this, D); +// } +// correct(); +// pos = (val.size() == 1 && val[0] == 0) ? true : oldpos; +// return *this; +} + +inline const InfInt& InfInt::operator*=(ELEM_TYPE rhs) +{ + //PROFINY_SCOPE + ELEM_TYPE factor = rhs < 0 ? -rhs : rhs; + bool oldpos = pos; + multiplyByDigit(factor, val); + correct(); + pos = (val.size() == 1 && val[0] == 0) ? true : (oldpos == (rhs >= 0)); + return *this; +} + +inline InfInt InfInt::operator-() const +{ + //PROFINY_SCOPE + InfInt result = *this; + result.pos = !pos; + return result; +} + +inline InfInt InfInt::operator+(const InfInt& rhs) const +{ + //PROFINY_SCOPE + InfInt result; + result.val.resize(val.size() > rhs.val.size() ? val.size() : rhs.val.size(), 0); + for (size_t i = 0; i < val.size() || i < rhs.val.size(); ++i) + { + result.val[i] = (i < val.size() ? (pos ? val[i] : -val[i]) : 0) + (i < rhs.val.size() ? (rhs.pos ? rhs.val[i] : -rhs.val[i]) : 0); + } + result.correct(); + return result; +} + +inline InfInt InfInt::operator-(const InfInt& rhs) const +{ + //PROFINY_SCOPE + InfInt result; + result.val.resize(val.size() > rhs.val.size() ? val.size() : rhs.val.size(), 0); + for (size_t i = 0; i < val.size() || i < rhs.val.size(); ++i) + { + result.val[i] = (i < val.size() ? (pos ? val[i] : -val[i]) : 0) - (i < rhs.val.size() ? (rhs.pos ? rhs.val[i] : -rhs.val[i]) : 0); + } + result.correct(); + return result; +} + +inline InfInt InfInt::operator*(const InfInt& rhs) const +{ + //PROFINY_SCOPE + InfInt result; + result.val.resize(val.size() + rhs.val.size(), 0); + PRODUCT_TYPE carry = 0; + size_t digit = 0; + for (;; ++digit) + { + lldiv_t dt = my_lldiv(carry, BASE); + carry = dt.quot; + result.val[digit] = (ELEM_TYPE) dt.rem; + + bool found = false; + for (size_t i = digit < rhs.val.size() ? 0 : digit - rhs.val.size() + 1; i < val.size() && i <= digit; ++i) + { + PRODUCT_TYPE pval = result.val[digit] + val[i] * (PRODUCT_TYPE) rhs.val[digit - i]; + if (pval >= BASE || pval <= -BASE) + { + lldiv_t dt = my_lldiv(pval, BASE); + carry += dt.quot; + pval = dt.rem; + } + result.val[digit] = (ELEM_TYPE) pval; + found = true; + } + if (!found) + { + break; + } + } + for (; carry > 0; ++digit) + { + lldiv_t dt = my_lldiv(carry, BASE); + result.val[digit] = (ELEM_TYPE) dt.rem; + carry = dt.quot; + } + result.correct(); + result.pos = (result.val.size() == 1 && result.val[0] == 0) ? true : (pos == rhs.pos); + return result; +} + +inline InfInt InfInt::operator/(const InfInt& rhs) const +{ + //PROFINY_SCOPE + if (rhs == 0) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("division by zero"); +#else + std::cerr << "Division by zero!" << std::endl; + return 0; +#endif + } + InfInt Q, R, D = (rhs.pos ? rhs : -rhs), N = (pos ? *this : -*this); + Q.val.resize(N.val.size(), 0); + for (int i = (int) N.val.size() - 1; i >= 0; --i) + { + R.val.insert(R.val.begin(), N.val[i]); + R.correct(true); + ELEM_TYPE cnt = dInR(R, D); + R -= D * cnt; + Q.val[i] += cnt; + } + Q.correct(); + Q.pos = (Q.val.size() == 1 && Q.val[0] == 0) ? true : (pos == rhs.pos); + return Q; +} + +inline InfInt InfInt::operator%(const InfInt& rhs) const +{ + //PROFINY_SCOPE + if (rhs == 0) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("division by zero"); +#else + std::cerr << "Division by zero!" << std::endl; + return 0; +#endif + } + InfInt R, D = (rhs.pos ? rhs : -rhs), N = (pos ? *this : -*this); + for (int i = (int) N.val.size() - 1; i >= 0; --i) + { + R.val.insert(R.val.begin(), N.val[i]); + R.correct(true); + R -= D * dInR(R, D); + } + R.correct(); + R.pos = (R.val.size() == 1 && R.val[0] == 0) ? true : pos; + return R; +} + +inline InfInt InfInt::operator*(ELEM_TYPE rhs) const +{ + //PROFINY_SCOPE + InfInt result = *this; + ELEM_TYPE factor = rhs < 0 ? -rhs : rhs; + multiplyByDigit(factor, result.val); + result.correct(); + result.pos = (result.val.size() == 1 && result.val[0] == 0) ? true : (pos == (rhs >= 0)); + return result; +} + +inline bool InfInt::operator==(const InfInt& rhs) const +{ + //PROFINY_SCOPE + if (pos != rhs.pos || val.size() != rhs.val.size()) + { + return false; + } + for (int i = (int) val.size() - 1; i >= 0; --i) + { + if (val[i] != rhs.val[i]) + { + return false; + } + } + return true; +} + +inline bool InfInt::operator!=(const InfInt& rhs) const +{ + //PROFINY_SCOPE + if (pos != rhs.pos || val.size() != rhs.val.size()) + { + return true; + } + for (int i = (int) val.size() - 1; i >= 0; --i) + { + if (val[i] != rhs.val[i]) + { + return true; + } + } + return false; +} + +inline bool InfInt::operator<(const InfInt& rhs) const +{ + //PROFINY_SCOPE + if (pos && !rhs.pos) + { + return false; + } + if (!pos && rhs.pos) + { + return true; + } + if (val.size() > rhs.val.size()) + { + return pos ? false : true; + } + if (val.size() < rhs.val.size()) + { + return pos ? true : false; + } + for (int i = (int) val.size() - 1; i >= 0; --i) + { + if (val[i] < rhs.val[i]) + { + return pos ? true : false; + } + if (val[i] > rhs.val[i]) + { + return pos ? false : true; + } + } + return false; +} + +inline bool InfInt::operator<=(const InfInt& rhs) const +{ + //PROFINY_SCOPE + if (pos && !rhs.pos) + { + return false; + } + if (!pos && rhs.pos) + { + return true; + } + if (val.size() > rhs.val.size()) + { + return pos ? false : true; + } + if (val.size() < rhs.val.size()) + { + return pos ? true : false; + } + for (int i = (int) val.size() - 1; i >= 0; --i) + { + if (val[i] < rhs.val[i]) + { + return pos ? true : false; + } + if (val[i] > rhs.val[i]) + { + return pos ? false : true; + } + } + return true; +} + +inline bool InfInt::operator>(const InfInt& rhs) const +{ + //PROFINY_SCOPE + if (pos && !rhs.pos) + { + return true; + } + if (!pos && rhs.pos) + { + return false; + } + if (val.size() > rhs.val.size()) + { + return pos ? true : false; + } + if (val.size() < rhs.val.size()) + { + return pos ? false : true; + } + for (int i = (int) val.size() - 1; i >= 0; --i) + { + if (val[i] < rhs.val[i]) + { + return pos ? false : true; + } + if (val[i] > rhs.val[i]) + { + return pos ? true : false; + } + } + return false; +} + +inline bool InfInt::operator>=(const InfInt& rhs) const +{ + //PROFINY_SCOPE + if (pos && !rhs.pos) + { + return true; + } + if (!pos && rhs.pos) + { + return false; + } + if (val.size() > rhs.val.size()) + { + return pos ? true : false; + } + if (val.size() < rhs.val.size()) + { + return pos ? false : true; + } + for (int i = (int) val.size() - 1; i >= 0; --i) + { + if (val[i] < rhs.val[i]) + { + return pos ? false : true; + } + if (val[i] > rhs.val[i]) + { + return pos ? true : false; + } + } + return true; +} + +inline void InfInt::optimizeSqrtSearchBounds(InfInt& lo, InfInt& hi) const +{ + //PROFINY_SCOPE + InfInt hdn = 1; + for (int i = (int) this->numberOfDigits() / 2; i >= 2; --i) + { + hdn *= 10; + } + if (lo < hdn) + { + lo = hdn; + } + hdn *= 100; + if (hi > hdn) + { + hi = hdn; + } +} + +inline InfInt InfInt::intSqrt() const +{ + //PROFINY_SCOPE + if (*this <= 0) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("intSqrt called for non-positive integer"); +#else + std::cerr << "intSqrt called for non-positive integer: " << *this << std::endl; + return 0; +#endif + } + InfInt hi = *this / 2 + 1, lo = 0, mid, mid2; + optimizeSqrtSearchBounds(lo, hi); + do + { + mid = (hi + lo) / 2; // 8 factor + mid2 = mid * mid; // 1 factor + if (mid2 == *this) + { + lo = mid; + break; + } + else if (mid2 < *this) + { + lo = mid; + } + else + { + hi = mid; + } + } while (lo < hi - 1 && mid2 != *this); + return lo; +} + +inline char InfInt::digitAt(size_t i) const +{ + //PROFINY_SCOPE + if (numberOfDigits() <= i) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("invalid digit index"); +#else + std::cerr << "Invalid digit index: " << i << std::endl; + return -1; +#endif + } + return (val[i / DIGIT_COUNT] / powersOfTen[i % DIGIT_COUNT]) % 10; +} + +inline size_t InfInt::numberOfDigits() const +{ + //PROFINY_SCOPE + return (val.size() - 1) * DIGIT_COUNT + + (val.back() > 99999999 ? 9 : (val.back() > 9999999 ? 8 : (val.back() > 999999 ? 7 : (val.back() > 99999 ? 6 : + (val.back() > 9999 ? 5 : (val.back() > 999 ? 4 : (val.back() > 99 ? 3 : (val.back() > 9 ? 2 : 1)))))))); +} + +inline std::string InfInt::toString() const +{ + //PROFINY_SCOPE + std::ostringstream oss; + oss << *this; + return oss.str(); +} + +inline size_t InfInt::size() const +{ + //PROFINY_SCOPE + return val.size() * sizeof(ELEM_TYPE) + sizeof(bool); +} + +inline int InfInt::toInt() const +{ + //PROFINY_SCOPE + if (*this > INT_MAX || *this < INT_MIN) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("out of bounds"); +#else + std::cerr << "Out of INT bounds: " << *this << std::endl; +#endif + } + int result = 0; + for (int i = (int) val.size() - 1; i >= 0; --i) + { + result = result * BASE + val[i]; + } + return pos ? result : -result; +} + +inline long InfInt::toLong() const +{ + //PROFINY_SCOPE + if (*this > LONG_MAX || *this < LONG_MIN) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("out of bounds"); +#else + std::cerr << "Out of LONG bounds: " << *this << std::endl; +#endif + } + long result = 0; + for (int i = (int) val.size() - 1; i >= 0; --i) + { + result = result * BASE + val[i]; + } + return pos ? result : -result; +} + +inline long long InfInt::toLongLong() const +{ + //PROFINY_SCOPE + if (*this > LONG_LONG_MAX || *this < LONG_LONG_MIN) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("out of bounds"); +#else + std::cerr << "Out of LLONG bounds: " << *this << std::endl; +#endif + } + long long result = 0; + for (int i = (int) val.size() - 1; i >= 0; --i) + { + result = result * BASE + val[i]; + } + return pos ? result : -result; +} + +inline unsigned int InfInt::toUnsignedInt() const +{ + //PROFINY_SCOPE + if (!pos || *this > UINT_MAX) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("out of bounds"); +#else + std::cerr << "Out of UINT bounds: " << *this << std::endl; +#endif + } + unsigned int result = 0; + for (int i = (int) val.size() - 1; i >= 0; --i) + { + result = result * BASE + val[i]; + } + return result; +} + +inline unsigned long InfInt::toUnsignedLong() const +{ + //PROFINY_SCOPE + if (!pos || *this > ULONG_MAX) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("out of bounds"); +#else + std::cerr << "Out of ULONG bounds: " << *this << std::endl; +#endif + } + unsigned long result = 0; + for (int i = (int) val.size() - 1; i >= 0; --i) + { + result = result * BASE + val[i]; + } + return result; +} + +inline unsigned long long InfInt::toUnsignedLongLong() const +{ + //PROFINY_SCOPE + if (!pos || *this > ULONG_LONG_MAX) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("out of bounds"); +#else + std::cerr << "Out of ULLONG bounds: " << *this << std::endl; +#endif + } + unsigned long long result = 0; + for (int i = (int) val.size() - 1; i >= 0; --i) + { + result = result * BASE + val[i]; + } + return result; +} + +inline void InfInt::truncateToBase() +{ + //PROFINY_SCOPE + for (size_t i = 0; i < val.size(); ++i) // truncate each + { + if (val[i] >= BASE || val[i] <= -BASE) + { + div_t dt = my_div(val[i], BASE); + val[i] = dt.rem; + if (i + 1 >= val.size()) + { + val.push_back(dt.quot); + } + else + { + val[i + 1] += dt.quot; + } + } + } +} + +inline bool InfInt::equalizeSigns() +{ + //PROFINY_SCOPE + bool isPositive = true; + int i = (int) ((val.size())) - 1; + for (; i >= 0; --i) + { + if (val[i] != 0) + { + isPositive = val[i--] > 0; + break; + } + } + + if (isPositive) + { + for (; i >= 0; --i) + { + if (val[i] < 0) + { + int k = 0, index = i + 1; + for (; (size_t)(index) < val.size() && val[index] == 0; ++k, ++index) + ; // count adjacent zeros on left + //if ((size_t)(index) < val.size() && val[index] > 0) + { // number on the left is positive + val[index] -= 1; + val[i] += BASE; + for (; k > 0; --k) + { + val[i + k] = UPPER_BOUND; + } + } + } + } + } + else + { + for (; i >= 0; --i) + { + if (val[i] > 0) + { + int k = 0, index = i + 1; + for (; (size_t)(index) < val.size() && val[index] == 0; ++k, ++index) + ; // count adjacent zeros on right + //if ((size_t)(index) < val.size() && val[index] < 0) + { // number on the left is negative + val[index] += 1; + val[i] -= BASE; + for (; k > 0; --k) + { + val[i + k] = -UPPER_BOUND; + } + } + } + } + } + + return isPositive; +} + +inline void InfInt::removeLeadingZeros() +{ + //PROFINY_SCOPE + for (int i = (int) (val.size()) - 1; i > 0; --i) // remove leading 0's + { + if (val[i] != 0) + { + return; + } + else + { + val.erase(val.begin() + i); + } + } +} + +inline void InfInt::correct(bool justCheckLeadingZeros, bool hasValidSign) +{ + //PROFINY_SCOPE + if (!justCheckLeadingZeros) + { + truncateToBase(); + + if (equalizeSigns()) + { + pos = ((val.size() == 1 && val[0] == 0) || !hasValidSign) ? true : pos; + } + else + { + pos = hasValidSign ? !pos : false; + for (size_t i = 0; i < val.size(); ++i) + { + val[i] = abs(val[i]); + } + } + } + + removeLeadingZeros(); +} + +inline void InfInt::fromString(const std::string& s) +{ + //PROFINY_SCOPE + pos = true; + val.clear(); + val.reserve(s.size() / DIGIT_COUNT + 1); + int i = (int) s.size() - DIGIT_COUNT; + for (; i >= 0; i -= DIGIT_COUNT) + { + val.push_back(atoi(s.substr(i, DIGIT_COUNT).c_str())); + } + if (i > -DIGIT_COUNT) + { + std::string ss = s.substr(0, i + DIGIT_COUNT); + if (ss.size() == 1 && ss[0] == '-') + { + pos = false; + } + else + { + val.push_back(atoi(ss.c_str())); + } + } + if (val.back() < 0) + { + val.back() = -val.back(); + pos = false; + } + correct(true); +} + +inline ELEM_TYPE InfInt::dInR(const InfInt& R, const InfInt& D) +{ + //PROFINY_SCOPE + ELEM_TYPE min = 0, max = UPPER_BOUND; + while (max > min) + { + ELEM_TYPE avg = max + min; + div_t dt = my_div(avg, 2); + avg = dt.rem ? (dt.quot + 1) : dt.quot; + InfInt prod = D * avg; + if (R == prod) + { + return avg; + } + else if (R > prod) + { + min = avg; + } + else + { + max = avg - 1; + } + } + return min; +} + +inline void InfInt::multiplyByDigit(ELEM_TYPE factor, std::vector& val) +{ + //PROFINY_SCOPE + ELEM_TYPE carry = 0; + for (size_t i = 0; i < val.size(); ++i) + { + PRODUCT_TYPE pval = val[i] * (PRODUCT_TYPE) factor + carry; + if (pval >= BASE || pval <= -BASE) + { + lldiv_t dt = my_lldiv(pval, BASE); + carry = (ELEM_TYPE) dt.quot; + pval = dt.rem; + } + else + { + carry = 0; + } + val[i] = (ELEM_TYPE) pval; + } + if (carry > 0) + { + val.push_back(carry); + } +} + +/**************************************************************/ +/******************** NON-MEMBER OPERATORS ********************/ +/**************************************************************/ + +inline std::istream& operator>>(std::istream &s, InfInt &n) +{ + //PROFINY_SCOPE + std::string str; + s >> str; + n.fromString(str); + return s; +} + +inline std::ostream& operator<<(std::ostream &s, const InfInt &n) +{ + //PROFINY_SCOPE + if (!n.pos) + { + s << '-'; + } + bool first = true; + for (int i = (int) n.val.size() - 1; i >= 0; --i) + { + if (first) + { + s << n.val[i]; + first = false; + } + else + { + s << std::setfill('0') << std::setw(DIGIT_COUNT) << n.val[i]; + } + } + return s; +} + +#endif diff --git a/libraries/chain/include/rlpvalue/src/rlp2json.cpp b/libraries/chain/include/rlpvalue/src/rlp2json.cpp new file mode 100644 index 00000000..c50ede3c --- /dev/null +++ b/libraries/chain/include/rlpvalue/src/rlp2json.cpp @@ -0,0 +1,107 @@ + +#include +#include +#include "rlpvalue.h" +#include "InfInt.h" + +extern void RLPtoJSON(const RLPValue& rval, UniValue& jval); +extern std::string encodeBinary(uint64_t n); + +static void assignJsonArray(UniValue& jval, const RLPValue& rval) +{ + jval.setArray(); + + const std::vector& values = rval.getValues(); + for (auto it = values.begin(); it != values.end(); it++) { + const RLPValue& childVal = *it; + UniValue childJval; + + RLPtoJSON(childVal, childJval); + + jval.push_back(childJval); + } +} + +static void assignJsonBuffer(UniValue& jval, const RLPValue& rval) +{ + jval.setStr(rval.getValStr()); +} + +void RLPtoJSON(const RLPValue& rval, UniValue& jval) +{ + if (rval.isBuffer()) + assignJsonBuffer(jval, rval); + else + assignJsonArray(jval, rval); +} + +static bool isBigNumStr(const std::string& s) +{ + // first char must be # + if (s.empty() || s[0] != '#') + return false; + + // remaining chars must be digits + for (unsigned int i = 1; i < s.size(); i++) + if (!isdigit(s[i])) + return false; + + return true; +} + +static std::string encodeBigNum(const InfInt& n) +{ + std::string rs; + + if (n == 0) { + // do nothing; return empty string + } else { + rs.assign(encodeBigNum(n / 256)); + + InfInt iich = n % 256; + unsigned char ch = iich.toUnsignedLong(); + rs.append((const char *) &ch, 1); + } + + return rs; +} + +static std::string encodeBigNumStr(const std::string& s) +{ + InfInt n(s); + return encodeBigNum(n); +} + +bool JSONtoRLP(const UniValue& jval, RLPValue& rval) +{ + if (jval.isStr()) { + std::string ins = jval.getValStr(); + if (isBigNumStr(ins)) + ins = encodeBigNumStr(ins.substr(1)); + + rval.assign(ins); + return true; + } + + if (jval.isNum()) { + uint64_t val = jval.get_int64(); + std::string val_enc = encodeBinary(val); + rval.assign(val_enc); + return true; + } + + if (jval.isArray()) { + rval.setArray(); + const std::vector& arrVals = jval.getValues(); + for (auto it = arrVals.begin(); it != arrVals.end(); it++) { + const UniValue& childJval = *it; + RLPValue tmp; + if (!JSONtoRLP(childJval, tmp)) + return false; + rval.push_back(tmp); + } + return true; + } + + return false; +} diff --git a/libraries/chain/include/rlpvalue/src/tool.cpp b/libraries/chain/include/rlpvalue/src/tool.cpp new file mode 100644 index 00000000..d17158e7 --- /dev/null +++ b/libraries/chain/include/rlpvalue/src/tool.cpp @@ -0,0 +1,189 @@ + +/* + * Copyright 2019 Bloq Inc. + * + */ + +#ifndef HAVE_CONFIG_H +#error missing autoconf-generated config.h. +#endif +#include "rlpvalue-config.h" + +#include +#include +#include +#include +#include "rlpvalue.h" +#include "../test/utilstrencodings.h" + +using namespace std; + +extern void RLPtoJSON(const RLPValue& rval, UniValue& jval); +extern bool JSONtoRLP(const UniValue& jval, RLPValue& rval); + +static const char doc[] = +"rlp - encode or decode RLP protocol encoding"; + +static struct argp_option options[] = { + { "decode", 'd', NULL, 0, + "Decode RLP to JSON" }, + { "encode", 'e', NULL, 0, + "Encode JSON to RLP (default)" }, + { } +}; + +static error_t parse_opt (int key, char *arg, struct argp_state *state); +static const struct argp argp = { options, parse_opt, NULL, doc }; + +static bool opt_decode = false; +static bool inp_json, inp_rlp, outp_json, outp_rlp; +static vector file_args; +static UniValue global_jval; +static RLPValue global_rval; + +static error_t parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) { + case 'd': opt_decode = true; break; + case 'e': opt_decode = false; break; + + case ARGP_KEY_ARG: + file_args.push_back(arg); + break; + + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + +static bool parseJsonInput(const std::string& body) +{ + bool rc = global_jval.read(body); + + if (!rc) + fprintf(stderr, "JSON input validation failed\n"); + + return rc; +} + +static bool parseRlpInput(const std::string& body) +{ + std::vector buf; + + if (body.substr(0, 2) == "0x") { + string tmp = body.substr(2); + buf = ParseHex(tmp); + } else + buf = ParseHex(body); + + size_t consumed, wanted; + bool rc = global_rval.read(&buf[0], buf.size(), consumed, wanted); + + if (!rc) + fprintf(stderr, "RLP input validation failed (%zu wanted)\n", + wanted); + + return rc; +} + +static bool readInput() +{ + if (opt_decode) { + inp_json = false; + inp_rlp = true; + outp_json = true; + outp_rlp = false; + } else { + inp_json = true; + inp_rlp = false; + outp_json = false; + outp_rlp = true; + } + + const char *filename = nullptr; + FILE *inf; + if (file_args.empty()) { + filename = "(standard input)"; + inf = stdin; + } else { + filename = file_args[0].c_str(); + inf = ::fopen(filename, "r"); + if (!inf) { + perror(filename); + return false; + } + } + + string body; + + while (1) { + vector buf(4096); + size_t rrc = fread(&buf[0], 1, buf.size(), inf); + body.append((char *) &buf[0], rrc); + if (rrc < buf.size()) + break; + } + bool haveErr = ferror(inf); + if (inf != stdin) + fclose(inf); + + if (haveErr) { + perror(filename); + return false; + } + + if (inp_json) + return parseJsonInput(body); + else + return parseRlpInput(body); +} + +static bool mutateInput() +{ + if (inp_rlp) + RLPtoJSON(global_rval, global_jval); + else + JSONtoRLP(global_jval, global_rval); + return true; +} + +static bool writeJsonOutput() +{ + string body = global_jval.write(2); + printf("%s\n", body.c_str()); + return true; +} + +static bool writeRlpOutput() +{ + string body = global_rval.write(); + string hex = HexStr(body.begin(), body.end()); + printf("%s\n", hex.c_str()); + return true; +} + +static bool writeOutput() +{ + if (outp_json) + return writeJsonOutput(); + else + return writeRlpOutput(); +} + +int main (int argc, char *argv[]) +{ + error_t argp_rc = argp_parse(&argp, argc, argv, 0, NULL, NULL); + if (argp_rc) { + fprintf(stderr, "%s: argp_parse failed: %s\n", + argv[0], strerror(argp_rc)); + return EXIT_FAILURE; + } + + if (!readInput() || !mutateInput() || !writeOutput()) + return 1; + + return 0; +} + diff --git a/libraries/chain/include/rlpvalue/test/.gitignore b/libraries/chain/include/rlpvalue/test/.gitignore new file mode 100644 index 00000000..7b27cf0d --- /dev/null +++ b/libraries/chain/include/rlpvalue/test/.gitignore @@ -0,0 +1,8 @@ + +object +unitester +test_json +no_nul + +*.trs +*.log diff --git a/libraries/chain/include/rlpvalue/test/data/example.json b/libraries/chain/include/rlpvalue/test/data/example.json new file mode 100644 index 00000000..e395204d --- /dev/null +++ b/libraries/chain/include/rlpvalue/test/data/example.json @@ -0,0 +1,6 @@ +{ + "listsoflists2": { + "in": "VALID", + "out": "c7c0c1c0c3c0c1c0" + } +} diff --git a/libraries/chain/include/rlpvalue/test/data/invalidRLPTest.json b/libraries/chain/include/rlpvalue/test/data/invalidRLPTest.json new file mode 100644 index 00000000..1f9b806c --- /dev/null +++ b/libraries/chain/include/rlpvalue/test/data/invalidRLPTest.json @@ -0,0 +1,46 @@ +{ + "int32Overflow": { + "in": "INVALID", + "out": "bf0f000000000000021111" + }, + + "int32Overflow2": { + "in": "INVALID", + "out": "ff0f000000000000021111" + }, + + "wrongSizeList": { + "in": "INVALID", + "out": "f80180" + }, + + "wrongSizeList2": { + "in": "INVALID", + "out": "f80100" + }, + + "incorrectLengthInArray": { + "in": "INVALID", + "out": "b9002100dc2b275d0f74e8a53e6f4ec61b27f24278820be3f82ea2110e582081b0565df0" + }, + + "randomRLP": { + "in": "INVALID", + "out": "f861f83eb9002100dc2b275d0f74e8a53e6f4ec61b27f24278820be3f82ea2110e582081b0565df027b90015002d5ef8325ae4d034df55d4b58d0dfba64d61ddd17be00000b9001a00dae30907045a2f66fa36f2bb8aa9029cbb0b8a7b3b5c435ab331" + }, + + "bytesShouldBeSingleByte00": { + "in": "INVALID", + "out": "8100" + }, + + "bytesShouldBeSingleByte01": { + "in": "INVALID", + "out": "8101" + }, + + "bytesShouldBeSingleByte7F": { + "in": "INVALID", + "out": "817F" + } +} diff --git a/libraries/chain/include/rlpvalue/test/data/longlist.json b/libraries/chain/include/rlpvalue/test/data/longlist.json new file mode 100644 index 00000000..525fe167 --- /dev/null +++ b/libraries/chain/include/rlpvalue/test/data/longlist.json @@ -0,0 +1,48 @@ +{ + "longList1" : { + "in" : [ + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"] + ], + "out": "0xf840cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376" + }, + "longList2" : { + "in" : [ + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"] + ], + "out": "0xf90200cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376" + } +} diff --git a/libraries/chain/include/rlpvalue/test/data/rlptest.json b/libraries/chain/include/rlpvalue/test/data/rlptest.json new file mode 100644 index 00000000..725022de --- /dev/null +++ b/libraries/chain/include/rlpvalue/test/data/rlptest.json @@ -0,0 +1,111 @@ +{ + "emptystring": { + "in": "", + "out": "0x80" + }, + "bytestring00": { + "in": "\u0000", + "out": "0x00" + }, + "bytestring01": { + "in": "\u0001", + "out": "0x01" + }, + "bytestring7F": { + "in": "\u007F", + "out": "0x7f" + }, + "shortstring": { + "in": "dog", + "out": "0x83646f67" + }, + "shortstring2": { + "in": "Lorem ipsum dolor sit amet, consectetur adipisicing eli", + "out": "0xb74c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e7365637465747572206164697069736963696e6720656c69" + }, + "longstring": { + "in": "Lorem ipsum dolor sit amet, consectetur adipisicing elit", + "out": "0xb8384c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e7365637465747572206164697069736963696e6720656c6974" + }, + "longstring2": { + "in": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur mauris magna, suscipit sed vehicula non, iaculis faucibus tortor. Proin suscipit ultricies malesuada. Duis tortor elit, dictum quis tristique eu, ultrices at risus. Morbi a est imperdiet mi ullamcorper aliquet suscipit nec lorem. Aenean quis leo mollis, vulputate elit varius, consequat enim. Nulla ultrices turpis justo, et posuere urna consectetur nec. Proin non convallis metus. Donec tempor ipsum in mauris congue sollicitudin. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse convallis sem vel massa faucibus, eget lacinia lacus tempor. Nulla quis ultricies purus. Proin auctor rhoncus nibh condimentum mollis. Aliquam consequat enim at metus luctus, a eleifend purus egestas. Curabitur at nibh metus. Nam bibendum, neque at auctor tristique, lorem libero aliquet arcu, non interdum tellus lectus sit amet eros. Cras rhoncus, metus ac ornare cursus, dolor justo ultrices metus, at ullamcorper volutpat", + "out": "0xb904004c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c69742e20437572616269747572206d6175726973206d61676e612c20737573636970697420736564207665686963756c61206e6f6e2c20696163756c697320666175636962757320746f72746f722e2050726f696e20737573636970697420756c74726963696573206d616c6573756164612e204475697320746f72746f7220656c69742c2064696374756d2071756973207472697374697175652065752c20756c7472696365732061742072697375732e204d6f72626920612065737420696d70657264696574206d6920756c6c616d636f7270657220616c6971756574207375736369706974206e6563206c6f72656d2e2041656e65616e2071756973206c656f206d6f6c6c69732c2076756c70757461746520656c6974207661726975732c20636f6e73657175617420656e696d2e204e756c6c6120756c74726963657320747572706973206a7573746f2c20657420706f73756572652075726e6120636f6e7365637465747572206e65632e2050726f696e206e6f6e20636f6e76616c6c6973206d657475732e20446f6e65632074656d706f7220697073756d20696e206d617572697320636f6e67756520736f6c6c696369747564696e2e20566573746962756c756d20616e746520697073756d207072696d697320696e206661756369627573206f726369206c756374757320657420756c74726963657320706f737565726520637562696c69612043757261653b2053757370656e646973736520636f6e76616c6c69732073656d2076656c206d617373612066617563696275732c2065676574206c6163696e6961206c616375732074656d706f722e204e756c6c61207175697320756c747269636965732070757275732e2050726f696e20617563746f722072686f6e637573206e69626820636f6e64696d656e74756d206d6f6c6c69732e20416c697175616d20636f6e73657175617420656e696d206174206d65747573206c75637475732c206120656c656966656e6420707572757320656765737461732e20437572616269747572206174206e696268206d657475732e204e616d20626962656e64756d2c206e6571756520617420617563746f72207472697374697175652c206c6f72656d206c696265726f20616c697175657420617263752c206e6f6e20696e74657264756d2074656c6c7573206c65637475732073697420616d65742065726f732e20437261732072686f6e6375732c206d65747573206163206f726e617265206375727375732c20646f6c6f72206a7573746f20756c747269636573206d657475732c20617420756c6c616d636f7270657220766f6c7574706174" + }, + "zero": { + "in": 0, + "out": "0x80" + }, + "smallint": { + "in": 1, + "out": "0x01" + }, + "smallint2": { + "in": 16, + "out": "0x10" + }, + "smallint3": { + "in": 79, + "out": "0x4f" + }, + "smallint4": { + "in": 127, + "out": "0x7f" + }, + "mediumint1": { + "in": 128, + "out": "0x8180" + }, + "mediumint2": { + "in": 1000, + "out": "0x8203e8" + }, + "mediumint3": { + "in": 100000, + "out": "0x830186a0" + }, + "mediumint4": { + "in": "#83729609699884896815286331701780722", + "out": "0x8f102030405060708090a0b0c0d0e0f2" + }, + "mediumint5": { + "in": "#105315505618206987246253880190783558935785933862974822347068935681", + "out": "0x9c0100020003000400050006000700080009000a000b000c000d000e01" + }, + "emptylist": { + "in": [], + "out": "0xc0" + }, + "stringlist": { + "in": [ "dog", "god", "cat" ], + "out": "0xcc83646f6783676f6483636174" + }, + "multilist": { + "in": [ "zw", [ 4 ], 1 ], + "out": "0xc6827a77c10401" + }, + "shortListMax1": { + "in": [ "asdf", "qwer", "zxcv", "asdf","qwer", "zxcv", "asdf", "qwer", "zxcv", "asdf", "qwer"], + "out": "0xf784617364668471776572847a78637684617364668471776572847a78637684617364668471776572847a78637684617364668471776572" + }, + "listsoflists": { + "in": [ [ [], [] ], [] ], + "out": "0xc4c2c0c0c0" + }, + "listsoflists2": { + "in": [ [], [[]], [ [], [[]] ] ], + "out": "0xc7c0c1c0c3c0c1c0" + }, + "dictTest1" : { + "in" : [ + ["key1", "val1"], + ["key2", "val2"], + ["key3", "val3"], + ["key4", "val4"] + ], + "out" : "0xecca846b6579318476616c31ca846b6579328476616c32ca846b6579338476616c33ca846b6579348476616c34" + }, + "bigint": { + "in": "#115792089237316195423570985008687907853269984665640564039457584007913129639936", + "out": "0xa1010000000000000000000000000000000000000000000000000000000000000000" + } +} diff --git a/libraries/chain/include/rlpvalue/test/object.cpp b/libraries/chain/include/rlpvalue/test/object.cpp new file mode 100644 index 00000000..9918f659 --- /dev/null +++ b/libraries/chain/include/rlpvalue/test/object.cpp @@ -0,0 +1,171 @@ +// Copyright (c) 2014 BitPay Inc. +// Copyright (c) 2014-2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include +#include +#include + +#define BOOST_FIXTURE_TEST_SUITE(a, b) +#define BOOST_AUTO_TEST_CASE(funcName) void funcName() +#define BOOST_AUTO_TEST_SUITE_END() +#define BOOST_CHECK(expr) assert(expr) +#define BOOST_CHECK_EQUAL(v1, v2) assert((v1) == (v2)) +#define BOOST_CHECK_THROW(stmt, excMatch) { \ + try { \ + (stmt); \ + assert(0 && "No exception caught"); \ + } catch (excMatch & e) { \ + } catch (...) { \ + assert(0 && "Wrong exception caught"); \ + } \ + } +#define BOOST_CHECK_NO_THROW(stmt) { \ + try { \ + (stmt); \ + } catch (...) { \ + assert(0); \ + } \ + } + +BOOST_FIXTURE_TEST_SUITE(rlpvalue_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(rlpvalue_constructor) +{ + RLPValue v2(RLPValue::VBUF); + BOOST_CHECK(v2.isBuffer()); + + RLPValue v3(RLPValue::VBUF); + v3.assign("foo"); + BOOST_CHECK(v3.isBuffer()); + BOOST_CHECK_EQUAL(v3.getValStr(), "foo"); + + std::string vs("yawn"); + RLPValue v8(vs); + BOOST_CHECK(v8.isBuffer()); + BOOST_CHECK_EQUAL(v8.getValStr(), "yawn"); + + const char *vcs = "zappa"; + RLPValue v9(vcs); + BOOST_CHECK(v9.isBuffer()); + BOOST_CHECK_EQUAL(v9.getValStr(), "zappa"); +} + +BOOST_AUTO_TEST_CASE(rlpvalue_set) +{ + RLPValue v("foo"); + v.clear(); + BOOST_CHECK_EQUAL(v.getValStr(), ""); + + BOOST_CHECK(v.setArray()); + BOOST_CHECK(v.isArray()); + BOOST_CHECK_EQUAL(v.size(), 0); + + v.assign("zum"); + BOOST_CHECK(v.isBuffer()); + BOOST_CHECK_EQUAL(v.getValStr(), "zum"); +} + +BOOST_AUTO_TEST_CASE(rlpvalue_array) +{ + RLPValue arr(RLPValue::VARR); + + std::string vStr("zippy"); + BOOST_CHECK(arr.push_back(vStr)); + + const char *s = "pippy"; + BOOST_CHECK(arr.push_back(s)); + + RLPValue v; + + std::vector vec; + v.assign("boing"); + vec.push_back(v); + + v.assign("going"); + vec.push_back(v); + + BOOST_CHECK(arr.push_backV(vec)); + + BOOST_CHECK_EQUAL(arr.empty(), false); + BOOST_CHECK_EQUAL(arr.size(), 4); + + BOOST_CHECK_EQUAL(arr[0].getValStr(), "zippy"); + BOOST_CHECK_EQUAL(arr[1].getValStr(), "pippy"); + BOOST_CHECK_EQUAL(arr[2].getValStr(), "boing"); + BOOST_CHECK_EQUAL(arr[3].getValStr(), "going"); + + BOOST_CHECK_EQUAL(arr[999].getValStr(), ""); + + arr.clear(); + BOOST_CHECK(arr.empty()); + BOOST_CHECK_EQUAL(arr.size(), 0); +} + +BOOST_AUTO_TEST_CASE(rlpvalue_readwrite) +{ + unsigned char s1[] = { 0x83, 'd', 'o', 'g' }; + + RLPValue v; + size_t consumed, wanted; + bool rc = v.read(&s1[0], sizeof(s1), consumed, wanted); + BOOST_CHECK(rc); + BOOST_CHECK(v.isBuffer()); + BOOST_CHECK_EQUAL(v.getValStr(), "dog"); + BOOST_CHECK_EQUAL(consumed, sizeof(s1)); + BOOST_CHECK_EQUAL(wanted, 0); + + std::string s1_out = v.write(); + BOOST_CHECK_EQUAL(sizeof(s1), s1_out.size()); + BOOST_CHECK_EQUAL(memcmp(&s1[0], &s1_out[0], sizeof(s1)), 0); + + unsigned char s2[] = + { 0xc8, 0x83, 'c', 'a', 't', 0x83, 'd', 'o', 'g' }; + + RLPValue v2; + rc = v2.read(&s2[0], sizeof(s2), consumed, wanted); + BOOST_CHECK(rc); + BOOST_CHECK(v2.isArray()); + BOOST_CHECK_EQUAL(consumed, sizeof(s2)); + BOOST_CHECK_EQUAL(wanted, 0); + BOOST_CHECK_EQUAL(v2[0].getValStr(), "cat"); + BOOST_CHECK_EQUAL(v2[1].getValStr(), "dog"); + + std::string s2_out = v2.write(); + BOOST_CHECK_EQUAL(sizeof(s2), s2_out.size()); + BOOST_CHECK_EQUAL(memcmp(&s2[0], &s2_out[0], sizeof(s2)), 0); + + unsigned char s_empty_list[] = { 0xc0 }; + RLPValue v_empty_list; + rc = v_empty_list.read(&s_empty_list[0], sizeof(s_empty_list), consumed, wanted); + BOOST_CHECK(rc); + BOOST_CHECK(v_empty_list.isArray()); + BOOST_CHECK_EQUAL(v_empty_list.size(), 0); + + unsigned char s_null[] = { 0x80 }; + RLPValue v_null; + rc = v_null.read(&s_null[0], sizeof(s_null), consumed, wanted); + BOOST_CHECK(rc); + BOOST_CHECK(v_null.isBuffer()); + BOOST_CHECK_EQUAL(v_null.getValStr(), ""); + BOOST_CHECK_EQUAL(consumed, sizeof(s_null)); + BOOST_CHECK_EQUAL(wanted, 0); +} + +BOOST_AUTO_TEST_SUITE_END() + +int main (int argc, char *argv[]) +{ + rlpvalue_constructor(); + rlpvalue_set(); + rlpvalue_array(); + rlpvalue_readwrite(); + return 0; +} + diff --git a/libraries/chain/include/rlpvalue/test/test_json.cpp b/libraries/chain/include/rlpvalue/test/test_json.cpp new file mode 100644 index 00000000..26828505 --- /dev/null +++ b/libraries/chain/include/rlpvalue/test/test_json.cpp @@ -0,0 +1,24 @@ +// Test program that can be called by the JSON test suite at +// https://github.com/nst/JSONTestSuite. +// +// It reads JSON input from stdin and exits with code 0 if it can be parsed +// successfully. It also pretty prints the parsed JSON value to stdout. + +#include +#include +#include "rlpvalue.h" + +using namespace std; + +int main (int argc, char *argv[]) +{ + RLPValue val; + if (val.read(string(istreambuf_iterator(cin), + istreambuf_iterator()))) { + cout << val.write() << endl; + return 0; + } else { + cerr << "JSON Parse Error." << endl; + return 1; + } +} diff --git a/libraries/chain/include/rlpvalue/test/unitester.cpp b/libraries/chain/include/rlpvalue/test/unitester.cpp new file mode 100644 index 00000000..b487ff0e --- /dev/null +++ b/libraries/chain/include/rlpvalue/test/unitester.cpp @@ -0,0 +1,207 @@ +// Copyright 2014 BitPay Inc. +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include +#include +#include "utilstrencodings.h" +#include "rlpvalue.h" +#include "../src/InfInt.h" + +using namespace std; + +#ifndef JSON_TEST_SRC +#error JSON_TEST_SRC must point to test source directory +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#endif + +std::string srcdir(JSON_TEST_SRC); +static bool test_failed = false; + +extern uint64_t toInteger(const unsigned char *raw, size_t len); +extern std::string encodeBinary(uint64_t n); +extern bool JSONtoRLP(const UniValue& jval, RLPValue& rval); + +static uint64_t toInteger(const char *raw, size_t len) { + return toInteger((const unsigned char *) raw, len); +} + +static bool isBigNumStr(const std::string& s) +{ + // first char must be # + if (s.empty() || s[0] != '#') + return false; + + // remaining chars must be digits + for (unsigned int i = 1; i < s.size(); i++) + if (!isdigit(s[i])) + return false; + + return true; +} + +static std::string encodeBigNum(const InfInt& n) +{ + std::string rs; + + if (n == 0) { + // do nothing; return empty string + } else { + rs.assign(encodeBigNum(n / 256)); + + InfInt iich = n % 256; + unsigned char ch = iich.toUnsignedLong(); + rs.append((const char *) &ch, 1); + } + + return rs; +} + +static std::string encodeBigNumStr(const std::string& s) +{ + InfInt n(s); + return encodeBigNum(n); +} + +static bool runtest(const std::string& filename, const std::string& key, + const UniValue& jval) +{ + if (!jval.isObject() || + !jval["out"].isStr()) { + fprintf(stderr, " %s: skipping test, invalid\n", + key.c_str()); + return true; + } + + string ins = jval["in"].getValStr(); + string outs = jval["out"].getValStr(); + + if (outs.substr(0, 2) == "0x") // remove 0x prefix + outs = outs.substr(2); + + // decode RLP binary output test string from hex to binary + std::vector outb = ParseHex(outs); + + // attempt to parse with RLP class + RLPValue v; + size_t consumed, wanted; + bool rrc = v.read(&outb[0], outb.size(), consumed, wanted); + + bool rc = false; + if (ins == "VALID" || ins == "INVALID") { + if (ins == "VALID" && rrc == true) + rc = true; + else if (ins == "INVALID" && rrc == false) + rc = true; + } else if (jval["in"].isStr()) { + if (isBigNumStr(ins)) + ins = encodeBigNumStr(ins.substr(1)); + + if (v.isBuffer() && (ins == v.getValStr())) + rc = true; + + } else if (jval["in"].isNum()) { + if (v.isBuffer()) { + uint64_t test_val = jval["in"].get_int64(); + string enc_val = v.getValStr(); + uint64_t dec_val = toInteger(&enc_val[0], + enc_val.size()); + if (test_val == dec_val) + rc = true; + } + } else if (jval["in"].isArray()) { + RLPValue root(RLPValue::VARR); + JSONtoRLP(jval["in"], root); + + std::string genOutput = root.write(); + if ((outb.size() == genOutput.size()) && + (memcmp(&outb[0], &genOutput[0], outb.size()) == 0)) { + rc = true; + } else { + std::string genHex = HexStr(genOutput.begin(), + genOutput.end()); + fprintf(stderr, "INS :%s\nGENS:%s\n", + outs.c_str(), + genHex.c_str()); + } + + } else { + fprintf(stderr, "ERR: test %s not implemented yet\n", key.c_str()); + } + + fprintf(stderr, " %s: %s\n", key.c_str(), + rc ? "ok" : "FAIL"); + return rc; +} + +static void runtest_jfile(std::string filename, const UniValue& jfile) +{ + assert(jfile.isObject()); + + const std::vector& keys = jfile.getKeys(); + + fprintf(stderr, "Running testfile %s (%zu tests)\n", + filename.c_str(), keys.size()); + + for (auto it = keys.begin(); it != keys.end(); it++) { + const std::string& key = *it; + if (!runtest(filename, key, jfile[key])) + test_failed = true; + } +} + +static void runtest_file(const char *filename_) +{ + std::string basename(filename_); + std::string filename = srcdir + "/" + basename; + FILE *f = fopen(filename.c_str(), "r"); + if (!f) { + perror(filename.c_str()); + exit(1); + } + + std::string jdata; + + char buf[4096]; + while (!feof(f)) { + int bread = fread(buf, 1, sizeof(buf), f); + assert(!ferror(f)); + + std::string s(buf, bread); + jdata += s; + } + + assert(!ferror(f)); + fclose(f); + + UniValue jfile; + bool rc = jfile.read(jdata); + assert(rc == true); + + runtest_jfile(basename, jfile); +} + +static const char *filenames[] = { + "example.json", + "invalidRLPTest.json", + "rlptest.json", +// "longlist.json", +}; + +int main (int argc, char *argv[]) +{ + for (unsigned int fidx = 0; fidx < ARRAY_SIZE(filenames); fidx++) { + runtest_file(filenames[fidx]); + } + + return test_failed ? 1 : 0; +} + diff --git a/libraries/chain/include/rlpvalue/test/utilstrencodings.cpp b/libraries/chain/include/rlpvalue/test/utilstrencodings.cpp new file mode 100644 index 00000000..901821c0 --- /dev/null +++ b/libraries/chain/include/rlpvalue/test/utilstrencodings.cpp @@ -0,0 +1,226 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2017 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "utilstrencodings.h" + +#include +#include +#include +#include + +static const std::string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + +const signed char p_util_hexdigit[256] = +{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1, + -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, }; + +signed char HexDigit(char c) +{ + return p_util_hexdigit[(unsigned char)c]; +} + +bool IsHex(const std::string& str) +{ + for(std::string::const_iterator it(str.begin()); it != str.end(); ++it) + { + if (HexDigit(*it) < 0) + return false; + } + return (str.size() > 0) && (str.size()%2 == 0); +} + +bool IsHexNumber(const std::string& str) +{ + size_t starting_location = 0; + if (str.size() > 2 && *str.begin() == '0' && *(str.begin()+1) == 'x') { + starting_location = 2; + } + for (auto c : str.substr(starting_location)) { + if (HexDigit(c) < 0) return false; + } + // Return false for empty string or "0x". + return (str.size() > starting_location); +} + +std::vector ParseHex(const char* psz) +{ + // convert hex dump to vector + std::vector vch; + while (true) + { + while (isspace(*psz)) + psz++; + signed char c = HexDigit(*psz++); + if (c == (signed char)-1) + break; + unsigned char n = (c << 4); + c = HexDigit(*psz++); + if (c == (signed char)-1) + break; + n |= c; + vch.push_back(n); + } + return vch; +} + +std::vector ParseHex(const std::string& str) +{ + return ParseHex(str.c_str()); +} + +std::string EncodeBase64(const unsigned char* pch, size_t len) +{ + static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + std::string strRet = ""; + strRet.reserve((len+2)/3*4); + + int mode=0, left=0; + const unsigned char *pchEnd = pch+len; + + while (pch> 2]; + left = (enc & 3) << 4; + mode = 1; + break; + + case 1: // we have two bits + strRet += pbase64[left | (enc >> 4)]; + left = (enc & 15) << 2; + mode = 2; + break; + + case 2: // we have four bits + strRet += pbase64[left | (enc >> 6)]; + strRet += pbase64[enc & 63]; + mode = 0; + break; + } + } + + if (mode) + { + strRet += pbase64[left]; + strRet += '='; + if (mode == 1) + strRet += '='; + } + + return strRet; +} + +std::string EncodeBase64(const std::string& str) +{ + return EncodeBase64((const unsigned char*)str.c_str(), str.size()); +} + +std::vector DecodeBase64(const char* p, bool* pfInvalid) +{ + static const int decode64_table[256] = + { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, + -1, -1, -1, -1, -1, 0, 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, -1, -1, -1, -1, -1, -1, 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, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }; + + if (pfInvalid) + *pfInvalid = false; + + std::vector vchRet; + vchRet.reserve(strlen(p)*3/4); + + int mode = 0; + int left = 0; + + while (1) + { + int dec = decode64_table[(unsigned char)*p]; + if (dec == -1) break; + p++; + switch (mode) + { + case 0: // we have no bits and get 6 + left = dec; + mode = 1; + break; + + case 1: // we have 6 bits and keep 4 + vchRet.push_back((left<<2) | (dec>>4)); + left = dec & 15; + mode = 2; + break; + + case 2: // we have 4 bits and get 6, we keep 2 + vchRet.push_back((left<<4) | (dec>>2)); + left = dec & 3; + mode = 3; + break; + + case 3: // we have 2 bits and get 6 + vchRet.push_back((left<<6) | dec); + mode = 0; + break; + } + } + + if (pfInvalid) + switch (mode) + { + case 0: // 4n base64 characters processed: ok + break; + + case 1: // 4n+1 base64 character processed: impossible + *pfInvalid = true; + break; + + case 2: // 4n+2 base64 characters processed: require '==' + if (left || p[0] != '=' || p[1] != '=' || decode64_table[(unsigned char)p[2]] != -1) + *pfInvalid = true; + break; + + case 3: // 4n+3 base64 characters processed: require '=' + if (left || p[0] != '=' || decode64_table[(unsigned char)p[1]] != -1) + *pfInvalid = true; + break; + } + + return vchRet; +} + +std::string DecodeBase64(const std::string& str) +{ + std::vector vchRet = DecodeBase64(str.c_str()); + return std::string((const char*)vchRet.data(), vchRet.size()); +} + diff --git a/libraries/chain/include/rlpvalue/test/utilstrencodings.h b/libraries/chain/include/rlpvalue/test/utilstrencodings.h new file mode 100644 index 00000000..6621ce4f --- /dev/null +++ b/libraries/chain/include/rlpvalue/test/utilstrencodings.h @@ -0,0 +1,62 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2017 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +/** + * Utilities for converting data from/to strings. + */ +#ifndef JUP_UTILSTRENCODINGS_H +#define JUP_UTILSTRENCODINGS_H + +#include +#include +#include + +#define BEGIN(a) ((char*)&(a)) +#define END(a) ((char*)&((&(a))[1])) +#define UBEGIN(a) ((unsigned char*)&(a)) +#define UEND(a) ((unsigned char*)&((&(a))[1])) +#define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0])) + +std::vector ParseHex(const char* psz); +std::vector ParseHex(const std::string& str); +signed char HexDigit(char c); +/* Returns true if each character in str is a hex character, and has an even + * number of hex digits.*/ +bool IsHex(const std::string& str); +/** +* Return true if the string is a hex number, optionally prefixed with "0x" +*/ +bool IsHexNumber(const std::string& str); +std::vector DecodeBase64(const char* p, bool* pfInvalid = nullptr); +std::string DecodeBase64(const std::string& str); +std::string EncodeBase64(const unsigned char* pch, size_t len); +std::string EncodeBase64(const std::string& str); + +template +std::string HexStr(const T itbegin, const T itend, bool fSpaces=false) +{ + std::string rv; + static const char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + rv.reserve((itend-itbegin)*3); + for(T it = itbegin; it < itend; ++it) + { + unsigned char val = (unsigned char)(*it); + if(fSpaces && it != itbegin) + rv.push_back(' '); + rv.push_back(hexmap[val>>4]); + rv.push_back(hexmap[val&15]); + } + + return rv; +} + +template +inline std::string HexStr(const T& vch, bool fSpaces=false) +{ + return HexStr(vch.begin(), vch.end(), fSpaces); +} + +#endif // JUP_UTILSTRENCODINGS_H diff --git a/libraries/chain/include/rlpvalue/univalue b/libraries/chain/include/rlpvalue/univalue new file mode 160000 index 00000000..d6715ee1 --- /dev/null +++ b/libraries/chain/include/rlpvalue/univalue @@ -0,0 +1 @@ +Subproject commit d6715ee16ed57bfbfc64e023dcb05151b6654aa4 diff --git a/libraries/chain/include/xgt/chain/contract_objects.hpp b/libraries/chain/include/xgt/chain/contract_objects.hpp index d75da723..37141926 100644 --- a/libraries/chain/include/xgt/chain/contract_objects.hpp +++ b/libraries/chain/include/xgt/chain/contract_objects.hpp @@ -1,7 +1,5 @@ #pragma once -#include - #include #include @@ -11,8 +9,6 @@ namespace xgt { namespace chain { - using uint256_t = boost::multiprecision::uint256_t; - class contract_object : public object< contract_object_type, contract_object > { XGT_STD_ALLOCATOR_CONSTRUCTOR( contract_object ) @@ -24,137 +20,113 @@ namespace xgt { namespace chain { } contract_id_type id; - wallet_name_type owner; + wallet_name_type owner; // Creator of wallet contract_hash_type contract_hash; + wallet_name_type wallet; vector code; }; struct by_id; - struct by_owner; struct by_contract_hash; + struct by_wallet; + struct by_owner_and_contract_hash; typedef multi_index_container< contract_object, indexed_by< ordered_unique< tag< by_id >, member< contract_object, contract_id_type, &contract_object::id > >, - ordered_unique< tag< by_owner >, member< contract_object, wallet_name_type, &contract_object::owner > >, - ordered_unique< tag< by_contract_hash >, member< contract_object, contract_hash_type, &contract_object::contract_hash > > + ordered_unique< tag< by_contract_hash >, member< contract_object, contract_hash_type, &contract_object::contract_hash > >, + ordered_unique< tag< by_wallet >, member< contract_object, wallet_name_type, &contract_object::wallet > >, + ordered_unique< tag< by_owner_and_contract_hash >, + composite_key< contract_object, + member< contract_object, wallet_name_type, &contract_object::owner >, + member< contract_object, contract_hash_type, &contract_object::contract_hash > + > + > >, allocator< contract_object > > contract_index; - // class contract_log_object : public object< contract_log_object_type, contract_log_object > - // { - // XGT_STD_ALLOCATOR_CONSTRUCTOR( contract_log_object ) - - // template< typename Constructor, typename Allocator > - // contract_log_object( Constructor&& c, allocator< Allocator > a ) - // { - // c( *this ); - // } - - // contract_log_id_type id; - // contract_id_type contract_id; - // wallet_name_type owner; - // uint8_t level; - // std::tuple< uint256_t, uint256_t, uint256_t, uint256_t > topics; - // vector data; - // }; - - // struct by_contract_id; - // // TODO: by_topic, by_level - - // // TODO: block id, transaction id, transaction op index? - // // TODO: Receipt object - // // https://github.com/ethereum/go-ethereum/tree/master/core/types - - // typedef multi_index_container< - // contract_log_object, - // indexed_by< - // ordered_unique< tag< by_contract_id >, member< contract_log_object, contract_id_type, &contract_log_object::contract_id > > - // >, - // allocator< contract_log_object > - // > contract_log_index; - - class contract_receipt_object : public object< contract_receipt_object_type, contract_receipt_object > + class contract_log_object : public object< contract_log_object_type, contract_log_object > { - XGT_STD_ALLOCATOR_CONSTRUCTOR( contract_receipt_object ) + XGT_STD_ALLOCATOR_CONSTRUCTOR( contract_log_object ) template< typename Constructor, typename Allocator > - contract_receipt_object( Constructor&& c, allocator< Allocator > a ) + contract_log_object( Constructor&& c, allocator< Allocator > a ) { c( *this ); } + contract_log_id_type id; contract_hash_type contract_hash; - wallet_name_type caller; - vector< vector > args; - // uint64_t energy_used; // TODO: Verify this + wallet_name_type owner; + std::vector topics; + vector data; }; typedef multi_index_container< - contract_receipt_object, + contract_log_object, indexed_by< - ordered_unique< tag< by_contract_hash >, member< contract_receipt_object, contract_hash_type, &contract_receipt_object::contract_hash > > + ordered_unique< tag< by_id >, member< contract_log_object, contract_log_id_type, &contract_log_object::id > > >, - allocator< contract_receipt_object > - > contract_receipt_index; - - // class contract_storage_object : public object< contract_storage_object_type, contract_storage_object > - // { - // XGT_STD_ALLOCATOR_CONSTRUCTOR( contract_storage_object ) - - // template< typename Constructor, typename Allocator > - // contract_storage_object( Constructor&& c, allocator< Allocator > a ) - // { - // c( *this ); - // } - - // contract_storage_id_type id; - // contract_id_type contract_id; - // wallet_name_type owner; // TODO: caller - // vector data; - // }; - - // struct by_contract_id; - // // TODO: By storage id and by owner id? - - // typedef multi_index_container< - // contract_storage_object, - // indexed_by< - // ordered_unique< tag< by_contract_id >, member< contract_storage_object, contract_id_type, &contract_storage_object::contract_id > > - // >, - // allocator< contract_storage_object > - // > contract_storage_index; + allocator< contract_log_object > + > contract_log_index; + + class contract_storage_object : public object< contract_storage_object_type, contract_storage_object > + { + XGT_STD_ALLOCATOR_CONSTRUCTOR( contract_storage_object ) + + template< typename Constructor, typename Allocator > + contract_storage_object( Constructor&& c, allocator< Allocator > a ) + { + c( *this ); + } + + contract_storage_id_type id; + contract_hash_type contract; + wallet_name_type caller; + map data; + }; + + struct by_contract_and_caller; + + typedef multi_index_container< + contract_storage_object, + indexed_by< + ordered_unique< tag< by_id >, member< contract_storage_object, contract_storage_id_type, &contract_storage_object::id > >, + ordered_unique< tag< by_contract_and_caller >, + composite_key< contract_storage_object, + member< contract_storage_object, contract_hash_type, &contract_storage_object::contract >, + member< contract_storage_object, wallet_name_type, &contract_storage_object::caller > + >, + composite_key_compare< std::less< contract_hash_type >, std::less< wallet_name_type > > + > + >, + allocator< contract_storage_object > + > contract_storage_index; } } FC_REFLECT( xgt::chain::contract_object, + (id) (owner) + (contract_hash) (code) ) CHAINBASE_SET_INDEX_TYPE( xgt::chain::contract_object, xgt::chain::contract_index ) -// FC_REFLECT( xgt::chain::contract_log_object, -// (id) -// (contract_id) -// (owner) -// (level) -// (topics) -// (data) ) -// CHAINBASE_SET_INDEX_TYPE( xgt::chain::contract_log_object, xgt::chain::contract_log_index ) - -FC_REFLECT( xgt::chain::contract_receipt_object, +FC_REFLECT( xgt::chain::contract_log_object, + (id) (contract_hash) - (caller) - (args) - // (energy_used) + (owner) + (topics) + (data) ) -CHAINBASE_SET_INDEX_TYPE( xgt::chain::contract_receipt_object, xgt::chain::contract_receipt_index ) - -// FC_REFLECT( xgt::chain::contract_storage_object, -// (id) -// (contract_id) -// (owner) -// (data) ) -// CHAINBASE_SET_INDEX_TYPE( xgt::chain::contract_storage_object, xgt::chain::contract_storage_index ) +CHAINBASE_SET_INDEX_TYPE( xgt::chain::contract_log_object, xgt::chain::contract_log_index ) + + FC_REFLECT( xgt::chain::contract_storage_object, + (id) + (contract) + (caller) + (data) ) + CHAINBASE_SET_INDEX_TYPE( xgt::chain::contract_storage_object, xgt::chain::contract_storage_index ) diff --git a/libraries/chain/include/xgt/chain/database.hpp b/libraries/chain/include/xgt/chain/database.hpp index 145b410b..33d08fbd 100644 --- a/libraries/chain/include/xgt/chain/database.hpp +++ b/libraries/chain/include/xgt/chain/database.hpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include @@ -201,11 +200,21 @@ namespace xgt { namespace chain { void foreach_operation(std::function processor) const; + const contract_storage_object& get_contract_storage( const contract_hash_type& owner, const wallet_name_type& caller )const; + const contract_storage_object* find_contract_storage( const contract_hash_type& owner, const wallet_name_type& caller )const; + const witness_object& get_witness( const wallet_name_type& name )const; const witness_object* find_witness( const wallet_name_type& name )const; + const contract_object& get_contract( const contract_hash_type& hash )const; + const contract_object& get_contract_by_wallet( const wallet_name_type& wallet )const; + const contract_object* find_contract( const contract_hash_type& hash )const; + const contract_object* find_contract_by_wallet( const wallet_name_type& wallet )const; + const wallet_object& get_account( const wallet_name_type& name )const; + const wallet_object& get_account_by_en_address( const en_address_type& en_address )const; const wallet_object* find_account( const wallet_name_type& name )const; + const wallet_object* find_account_by_en_address( const en_address_type& en_address )const; const comment_object& get_comment( const wallet_name_type& author, const shared_string& permlink )const; const comment_object* find_comment( const wallet_name_type& author, const shared_string& permlink )const; @@ -218,8 +227,6 @@ namespace xgt { namespace chain { const escrow_object& get_escrow( const wallet_name_type& name, uint32_t escrow_id )const; const escrow_object* find_escrow( const wallet_name_type& name, uint32_t escrow_id )const; - //const contract_object& get_contract( const contract_hash_type& contract_hash )const; - const dynamic_global_property_object& get_dynamic_global_properties()const; const node_property_object& get_node_properties()const; const hardfork_property_object& get_hardfork_property_object()const; @@ -400,6 +407,29 @@ namespace xgt { namespace chain { void validate_xtt_invariants()const; ///@} + fc::optional get_block_hash_from_block_num(uint32_t block_num) const + { + auto block = _block_log.read_block_by_num(block_num); + if (block) { + for( const auto& trx : block->transactions ) + { + + const auto& operations = trx.operations; + for (auto& op : operations) + { + if ( is_pow_operation(op) ) + { + const protocol::pow_operation& o = op.template get< protocol::pow_operation >(); + // TODO: May need a check to verify it is sha2_pow before continuing + const auto& work = o.work.get< sha2_pow >(); + return fc::optional(work.proof); + } + } + } + } + return fc::optional(); + } + protected: //Mark pop_undo() as protected -- we do not want outside calling pop_undo(); it should call pop_block() instead //void pop_undo() { object_database::pop_undo(); } @@ -473,6 +503,22 @@ namespace xgt { namespace chain { return _hardfork_versions; } + fc::sha256 bigint_to_hash(boost::multiprecision::uint256_t b) + { + std::ostringstream os; + os << std::hex << std::setw(64) << std::setfill('0') << b; + std::string string_hash = os.str(); + return fc::sha256(string_hash); + } + + boost::multiprecision::uint256_t hash_to_bigint(fc::sha256 h) + { + std::string prefix = "0x"; + std::string string_hash = h.str(); + std::string prepended_string_hash = prefix.append(string_hash); + return boost::multiprecision::uint256_t(prepended_string_hash); + } + private: std::unique_ptr< database_impl > _my; diff --git a/libraries/chain/include/xgt/chain/global_property_object.hpp b/libraries/chain/include/xgt/chain/global_property_object.hpp index 3a44e3dc..1d360d12 100644 --- a/libraries/chain/include/xgt/chain/global_property_object.hpp +++ b/libraries/chain/include/xgt/chain/global_property_object.hpp @@ -110,6 +110,12 @@ namespace xgt { namespace chain { uint16_t downvote_pool_percent = 0; asset xtt_creation_fee = asset( 1000, XGT_SYMBOL ); + + // Virtual machine energy implementation + + int64_t energy_multiplier; + + int64_t energy_interval; }; typedef multi_index_container< diff --git a/libraries/chain/include/xgt/chain/machine.hpp b/libraries/chain/include/xgt/chain/machine.hpp deleted file mode 100644 index e5e160e8..00000000 --- a/libraries/chain/include/xgt/chain/machine.hpp +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace xgt { namespace chain { - - namespace detail { class machine_impl; } - - typedef uint8_t machine_word; - typedef uint64_t machine_big_word; - typedef uint64_t machine_address; - - enum class machine_opcode { - stop_opcode = 0x00, - add_opcode = 0x01, - mul_opcode = 0x02, - sub_opcode = 0x03, - div_opcode = 0x04, - sdiv_opcode = 0x05, - mod_opcode = 0x06, - smod_opcode = 0x07, - // TODO: addmod 0x08 - // TODO: mulmod 0x09 - // TODO: exp 0x0a - // TODO: signextend 0x0b - lt_opcode = 0x10, - gt_opcode = 0x11, - // TODO: slt 0x12 - // TODO: sgt 0x13 - // TODO: eq 0x14 - // TODO: iszero 0x15 - // TODO: Gap... - timestamp_opcode = 0x42, - // TODO: Gap... - jumpi_opcode = 0x57, - // TODO: Gap... - mload_opcode = 0x51, - mstore_opcode = 0x52, - // TODO: Gap... - jumpdest_opcode = 0x5b, - // TODO: Gap... - push1_opcode = 0x60, - push2_opcode = 0x61, - push3_opcode = 0x62, - push4_opcode = 0x63, - // TODO: Gap... - dup1_opcode = 0x80, - // TODO: Gap... - swap1_opcode = 0x90, - swap2_opcode = 0x91, - swap3_opcode = 0x92, - swap4_opcode = 0x93, - // TODO: Gap... - return_opcode = 0xf3, - // TODO: Gap... - }; - - enum class machine_state { - stopped, - running, - error - }; - - struct machine_context - { - bool is_debug; - uint64_t block_timestamp; - }; - - struct machine { - - machine(machine_context ctx, std::vector code); - ~machine(); - - std::unique_ptr my; - - void step(); - - }; - -} } diff --git a/libraries/chain/include/xgt/chain/util/energybar.hpp b/libraries/chain/include/xgt/chain/util/energybar.hpp index 6c0462d0..4b2f303b 100644 --- a/libraries/chain/include/xgt/chain/util/energybar.hpp +++ b/libraries/chain/include/xgt/chain/util/energybar.hpp @@ -100,11 +100,17 @@ struct energybar template< typename PropType, typename AccountType > void update_energybar( const PropType& gpo, AccountType& account, int32_t energy_regen_seconds, bool downvote_energy = false, int64_t new_energy = 0 ) { + try + { + energybar_params params( static_cast(account.balance.amount.value), energy_regen_seconds ); + account.energybar.regenerate_energy( params, gpo.time ); + account.energybar.use_energy( -new_energy ); + } FC_CAPTURE_LOG_AND_RETHROW( (account)(account.balance.amount) ) } } } } // xgt::chain::util FC_REFLECT( xgt::chain::util::energybar, - (current_energy) - (last_update_time) - ) + (current_energy) + (last_update_time) + ) diff --git a/libraries/chain/include/xgt/chain/wallet_object.hpp b/libraries/chain/include/xgt/chain/wallet_object.hpp index 51b81373..ea4ad90b 100644 --- a/libraries/chain/include/xgt/chain/wallet_object.hpp +++ b/libraries/chain/include/xgt/chain/wallet_object.hpp @@ -31,6 +31,10 @@ namespace xgt { namespace chain { id_type id; wallet_name_type name; + // TODO EN_ADDRESS INSTEAD OF en_address if possible, in addition to otherwise. + // Machine processes en_address_type as a uint256_t, but en_address needs to be preserved + // Maybe lookup wallet based on en_address and grab en_address + en_address_type en_address; public_key_type memo_key; time_point_sec last_account_update; @@ -43,6 +47,7 @@ namespace xgt { namespace chain { uint32_t comment_count = 0; uint32_t lifetime_vote_count = 0; uint32_t post_count = 0; + uint32_t nonce = 0; bool can_vote = true; util::energybar energybar; @@ -90,6 +95,7 @@ namespace xgt { namespace chain { id_type id; wallet_name_type account; + en_address_type en_address; shared_authority recovery; ///< used for backup control, can set recovery or money shared_authority money; ///< used for all monetary operations, can set money or social @@ -163,7 +169,9 @@ namespace xgt { namespace chain { ordered_unique< tag< by_id >, member< wallet_object, wallet_id_type, &wallet_object::id > >, ordered_unique< tag< by_name >, - member< wallet_object, wallet_name_type, &wallet_object::name > > + member< wallet_object, wallet_name_type, &wallet_object::name > >, + ordered_unique< tag< by_en_address >, + member< wallet_object, en_address_type, &wallet_object::en_address > > >, allocator< wallet_object > > wallet_index; diff --git a/libraries/chain/include/xgt/chain/xgt_object_types.hpp b/libraries/chain/include/xgt/chain/xgt_object_types.hpp index 9f9dd0e3..6ffc46da 100644 --- a/libraries/chain/include/xgt/chain/xgt_object_types.hpp +++ b/libraries/chain/include/xgt/chain/xgt_object_types.hpp @@ -42,6 +42,7 @@ using xgt::protocol::block_id_type; using xgt::protocol::transaction_id_type; using xgt::protocol::chain_id_type; using xgt::protocol::wallet_name_type; +using xgt::protocol::en_address_type; using xgt::protocol::share_type; using chainbase::shared_string; @@ -51,6 +52,7 @@ inline void from_string( shared_string& out, const string& in ){ out.assign( in. struct by_id; struct by_name; +struct by_en_address; enum object_type { @@ -60,7 +62,6 @@ enum object_type account_authority_object_type, contract_object_type, contract_log_object_type, - contract_receipt_object_type, contract_storage_object_type, witness_object_type, transaction_object_type, @@ -104,6 +105,7 @@ class wallet_object; class account_metadata_object; class account_authority_object; class contract_object; +class contract_log_object; class contract_storage_object; class witness_object; class transaction_object; @@ -147,6 +149,7 @@ typedef oid< wallet_object > wallet_id_type; typedef oid< account_metadata_object > account_metadata_id_type; typedef oid< account_authority_object > account_authority_id_type; typedef oid< contract_object > contract_id_type; +typedef oid< contract_log_object > contract_log_id_type; typedef oid< contract_storage_object > contract_storage_id_type; typedef oid< witness_object > witness_id_type; typedef oid< transaction_object > transaction_object_id_type; @@ -361,7 +364,6 @@ FC_REFLECT_ENUM( xgt::chain::object_type, (account_authority_object_type) (contract_object_type) (contract_log_object_type) - (contract_receipt_object_type) (contract_storage_object_type) (witness_object_type) (transaction_object_type) diff --git a/libraries/chain/index.cpp b/libraries/chain/index.cpp index c34259fa..a05a77bc 100644 --- a/libraries/chain/index.cpp +++ b/libraries/chain/index.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace xgt { namespace chain { @@ -41,6 +42,8 @@ void initialize_core_indexes( database& db ) XGT_ADD_CORE_INDEX(db, xtt_ico_index); XGT_ADD_CORE_INDEX(db, xtt_ico_tier_index); XGT_ADD_CORE_INDEX(db, contract_index); + XGT_ADD_CORE_INDEX(db, contract_log_index); + XGT_ADD_CORE_INDEX(db, contract_storage_index); } index_info::index_info() {} diff --git a/libraries/chain/keccak.c b/libraries/chain/keccak.c new file mode 100644 index 00000000..04b38a38 --- /dev/null +++ b/libraries/chain/keccak.c @@ -0,0 +1,382 @@ +// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +// Copyright 2018 Pawel Bylica. +// SPDX-License-Identifier: Apache-2.0 + +#include "attributes.h" +#include "keccak.h" + +#if !__has_builtin(__builtin_memcpy) && !defined(__GNUC__) +#include +#define __builtin_memcpy memcpy +#endif + +#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define to_le64(X) __builtin_bswap64(X) +#else +#define to_le64(X) X +#endif + +/// Loads 64-bit integer from given memory location as little-endian number. +static inline ALWAYS_INLINE uint64_t load_le(const uint8_t* data) +{ + /* memcpy is the best way of expressing the intention. Every compiler will + optimize is to single load instruction if the target architecture + supports unaligned memory access (GCC and clang even in O0). + This is great trick because we are violating C/C++ memory alignment + restrictions with no performance penalty. */ + uint64_t word; + __builtin_memcpy(&word, data, sizeof(word)); + return to_le64(word); +} + +/// Rotates the bits of x left by the count value specified by s. +/// The s must be in range <0, 64> exclusively, otherwise the result is undefined. +static inline uint64_t rol(uint64_t x, unsigned s) +{ + return (x << s) | (x >> (64 - s)); +} + +static const uint64_t round_constants[24] = { // + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000, + 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009, + 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003, + 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a, + 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008}; + + +/// The Keccak-f[1600] function. +/// +/// The implementation of the Keccak-f function with 1600-bit width of the permutation (b). +/// The size of the state is also 1600 bit what gives 25 64-bit words. +/// +/// @param state The state of 25 64-bit words on which the permutation is to be performed. +/// +/// The implementation based on: +/// - "simple" implementation by Ronny Van Keer, included in "Reference and optimized code in C", +/// https://keccak.team/archives.html, CC0-1.0 / Public Domain. +static inline ALWAYS_INLINE void keccakf1600_implementation(uint64_t state[25]) +{ + uint64_t Aba, Abe, Abi, Abo, Abu; + uint64_t Aga, Age, Agi, Ago, Agu; + uint64_t Aka, Ake, Aki, Ako, Aku; + uint64_t Ama, Ame, Ami, Amo, Amu; + uint64_t Asa, Ase, Asi, Aso, Asu; + + uint64_t Eba, Ebe, Ebi, Ebo, Ebu; + uint64_t Ega, Ege, Egi, Ego, Egu; + uint64_t Eka, Eke, Eki, Eko, Eku; + uint64_t Ema, Eme, Emi, Emo, Emu; + uint64_t Esa, Ese, Esi, Eso, Esu; + + uint64_t Ba, Be, Bi, Bo, Bu; + + uint64_t Da, De, Di, Do, Du; + + Aba = state[0]; + Abe = state[1]; + Abi = state[2]; + Abo = state[3]; + Abu = state[4]; + Aga = state[5]; + Age = state[6]; + Agi = state[7]; + Ago = state[8]; + Agu = state[9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for (size_t n = 0; n < 24; n += 2) + { + // Round (n + 0): Axx -> Exx + + Ba = Aba ^ Aga ^ Aka ^ Ama ^ Asa; + Be = Abe ^ Age ^ Ake ^ Ame ^ Ase; + Bi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; + Bo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; + Bu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; + + Da = Bu ^ rol(Be, 1); + De = Ba ^ rol(Bi, 1); + Di = Be ^ rol(Bo, 1); + Do = Bi ^ rol(Bu, 1); + Du = Bo ^ rol(Ba, 1); + + Ba = Aba ^ Da; + Be = rol(Age ^ De, 44); + Bi = rol(Aki ^ Di, 43); + Bo = rol(Amo ^ Do, 21); + Bu = rol(Asu ^ Du, 14); + Eba = Ba ^ (~Be & Bi) ^ round_constants[n]; + Ebe = Be ^ (~Bi & Bo); + Ebi = Bi ^ (~Bo & Bu); + Ebo = Bo ^ (~Bu & Ba); + Ebu = Bu ^ (~Ba & Be); + + Ba = rol(Abo ^ Do, 28); + Be = rol(Agu ^ Du, 20); + Bi = rol(Aka ^ Da, 3); + Bo = rol(Ame ^ De, 45); + Bu = rol(Asi ^ Di, 61); + Ega = Ba ^ (~Be & Bi); + Ege = Be ^ (~Bi & Bo); + Egi = Bi ^ (~Bo & Bu); + Ego = Bo ^ (~Bu & Ba); + Egu = Bu ^ (~Ba & Be); + + Ba = rol(Abe ^ De, 1); + Be = rol(Agi ^ Di, 6); + Bi = rol(Ako ^ Do, 25); + Bo = rol(Amu ^ Du, 8); + Bu = rol(Asa ^ Da, 18); + Eka = Ba ^ (~Be & Bi); + Eke = Be ^ (~Bi & Bo); + Eki = Bi ^ (~Bo & Bu); + Eko = Bo ^ (~Bu & Ba); + Eku = Bu ^ (~Ba & Be); + + Ba = rol(Abu ^ Du, 27); + Be = rol(Aga ^ Da, 36); + Bi = rol(Ake ^ De, 10); + Bo = rol(Ami ^ Di, 15); + Bu = rol(Aso ^ Do, 56); + Ema = Ba ^ (~Be & Bi); + Eme = Be ^ (~Bi & Bo); + Emi = Bi ^ (~Bo & Bu); + Emo = Bo ^ (~Bu & Ba); + Emu = Bu ^ (~Ba & Be); + + Ba = rol(Abi ^ Di, 62); + Be = rol(Ago ^ Do, 55); + Bi = rol(Aku ^ Du, 39); + Bo = rol(Ama ^ Da, 41); + Bu = rol(Ase ^ De, 2); + Esa = Ba ^ (~Be & Bi); + Ese = Be ^ (~Bi & Bo); + Esi = Bi ^ (~Bo & Bu); + Eso = Bo ^ (~Bu & Ba); + Esu = Bu ^ (~Ba & Be); + + + // Round (n + 1): Exx -> Axx + + Ba = Eba ^ Ega ^ Eka ^ Ema ^ Esa; + Be = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; + Bi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; + Bo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; + Bu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; + + Da = Bu ^ rol(Be, 1); + De = Ba ^ rol(Bi, 1); + Di = Be ^ rol(Bo, 1); + Do = Bi ^ rol(Bu, 1); + Du = Bo ^ rol(Ba, 1); + + Ba = Eba ^ Da; + Be = rol(Ege ^ De, 44); + Bi = rol(Eki ^ Di, 43); + Bo = rol(Emo ^ Do, 21); + Bu = rol(Esu ^ Du, 14); + Aba = Ba ^ (~Be & Bi) ^ round_constants[n + 1]; + Abe = Be ^ (~Bi & Bo); + Abi = Bi ^ (~Bo & Bu); + Abo = Bo ^ (~Bu & Ba); + Abu = Bu ^ (~Ba & Be); + + Ba = rol(Ebo ^ Do, 28); + Be = rol(Egu ^ Du, 20); + Bi = rol(Eka ^ Da, 3); + Bo = rol(Eme ^ De, 45); + Bu = rol(Esi ^ Di, 61); + Aga = Ba ^ (~Be & Bi); + Age = Be ^ (~Bi & Bo); + Agi = Bi ^ (~Bo & Bu); + Ago = Bo ^ (~Bu & Ba); + Agu = Bu ^ (~Ba & Be); + + Ba = rol(Ebe ^ De, 1); + Be = rol(Egi ^ Di, 6); + Bi = rol(Eko ^ Do, 25); + Bo = rol(Emu ^ Du, 8); + Bu = rol(Esa ^ Da, 18); + Aka = Ba ^ (~Be & Bi); + Ake = Be ^ (~Bi & Bo); + Aki = Bi ^ (~Bo & Bu); + Ako = Bo ^ (~Bu & Ba); + Aku = Bu ^ (~Ba & Be); + + Ba = rol(Ebu ^ Du, 27); + Be = rol(Ega ^ Da, 36); + Bi = rol(Eke ^ De, 10); + Bo = rol(Emi ^ Di, 15); + Bu = rol(Eso ^ Do, 56); + Ama = Ba ^ (~Be & Bi); + Ame = Be ^ (~Bi & Bo); + Ami = Bi ^ (~Bo & Bu); + Amo = Bo ^ (~Bu & Ba); + Amu = Bu ^ (~Ba & Be); + + Ba = rol(Ebi ^ Di, 62); + Be = rol(Ego ^ Do, 55); + Bi = rol(Eku ^ Du, 39); + Bo = rol(Ema ^ Da, 41); + Bu = rol(Ese ^ De, 2); + Asa = Ba ^ (~Be & Bi); + Ase = Be ^ (~Bi & Bo); + Asi = Bi ^ (~Bo & Bu); + Aso = Bo ^ (~Bu & Ba); + Asu = Bu ^ (~Ba & Be); + } + + state[0] = Aba; + state[1] = Abe; + state[2] = Abi; + state[3] = Abo; + state[4] = Abu; + state[5] = Aga; + state[6] = Age; + state[7] = Agi; + state[8] = Ago; + state[9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; +} + +static void keccakf1600_generic(uint64_t state[25]) +{ + keccakf1600_implementation(state); +} + +/// The pointer to the best Keccak-f[1600] function implementation, +/// selected during runtime initialization. +static void (*keccakf1600_best)(uint64_t[25]) = keccakf1600_generic; + + +#if !defined(_MSC_VER) && defined(__x86_64__) && __has_attribute(target) +__attribute__((target("bmi,bmi2"))) static void keccakf1600_bmi(uint64_t state[25]) +{ + keccakf1600_implementation(state); +} + +__attribute__((constructor)) static void select_keccakf1600_implementation() +{ + // Init CPU information. + // This is needed on macOS because of the bug: https://bugs.llvm.org/show_bug.cgi?id=48459. + __builtin_cpu_init(); + + // Check if both BMI and BMI2 are supported. Some CPUs like Intel E5-2697 v2 incorrectly + // report BMI2 but not BMI being available. + if (__builtin_cpu_supports("bmi") && __builtin_cpu_supports("bmi2")) + keccakf1600_best = keccakf1600_bmi; +} +#endif + + +static inline ALWAYS_INLINE void keccak( + uint64_t* out, size_t bits, const uint8_t* data, size_t size) +{ + static const size_t word_size = sizeof(uint64_t); + const size_t hash_size = bits / 8; + const size_t block_size = (1600 - bits * 2) / 8; + + size_t i; + uint64_t* state_iter; + uint64_t last_word = 0; + uint8_t* last_word_iter = (uint8_t*)&last_word; + + uint64_t state[25] = {0}; + + while (size >= block_size) + { + for (i = 0; i < (block_size / word_size); ++i) + { + state[i] ^= load_le(data); + data += word_size; + } + + keccakf1600_best(state); + + size -= block_size; + } + + state_iter = state; + + while (size >= word_size) + { + *state_iter ^= load_le(data); + ++state_iter; + data += word_size; + size -= word_size; + } + + while (size > 0) + { + *last_word_iter = *data; + ++last_word_iter; + ++data; + --size; + } + *last_word_iter = 0x01; + *state_iter ^= to_le64(last_word); + + state[(block_size / word_size) - 1] ^= 0x8000000000000000; + + keccakf1600_best(state); + + for (i = 0; i < (hash_size / word_size); ++i) + out[i] = to_le64(state[i]); +} + +union ethash_hash256 ethash_keccak256(const uint8_t* data, size_t size) +{ + union ethash_hash256 hash; + keccak(hash.word64s, 256, data, size); + return hash; +} + +union ethash_hash256 ethash_keccak256_32(const uint8_t data[32]) +{ + union ethash_hash256 hash; + keccak(hash.word64s, 256, data, 32); + return hash; +} + +union ethash_hash512 ethash_keccak512(const uint8_t* data, size_t size) +{ + union ethash_hash512 hash; + keccak(hash.word64s, 512, data, size); + return hash; +} + +union ethash_hash512 ethash_keccak512_64(const uint8_t data[64]) +{ + union ethash_hash512 hash; + keccak(hash.word64s, 512, data, 64); + return hash; +} diff --git a/libraries/chain/keccak256.c b/libraries/chain/keccak256.c new file mode 100644 index 00000000..f4e1f1de --- /dev/null +++ b/libraries/chain/keccak256.c @@ -0,0 +1,245 @@ +/* sha3 - an implementation of Secure Hash Algorithm 3 (Keccak). + * based on the + * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011 + * by Guido Bertoni, Joan Daemen, Michaƫl Peeters and Gilles Van Assche + * + * Copyright: 2013 Aleksey Kravchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so. + * + * This program 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. Use this program at your own risk! + */ + +#include "keccak256.h" + +//#include + +#include +#include + +#define BLOCK_SIZE ((1600 - 256 * 2) / 8) + +#define I64(x) x##LL +#define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n)))) +#define le2me_64(x) (x) +#define IS_ALIGNED_64(p) (0 == (7 & ((const char*)(p) - (const char*)0))) +#define me64_to_le_str(to, from, length) memcpy((to), (from), (length)) + +/* constants */ + +//const uint8_t round_constant_info[] PROGMEM = { +//const uint8_t constants[] PROGMEM = { +const uint8_t constants[] = { + + 1, 26, 94, 112, 31, 33, 121, 85, 14, 12, 53, 38, 63, 79, 93, 83, 82, 72, 22, 102, 121, 88, 33, 116, +//}; + +//const uint8_t pi_transform[] PROGMEM = { + 1, 6, 9, 22, 14, 20, 2, 12, 13, 19, 23, 15, 4, 24, 21, 8, 16, 5, 3, 18, 17, 11, 7, 10, +//}; + +//const uint8_t rhoTransforms[] PROGMEM = { + 1, 62, 28, 27, 36, 44, 6, 55, 20, 3, 10, 43, 25, 39, 41, 45, 15, 21, 8, 18, 2, 61, 56, 14, +}; + +#define TYPE_ROUND_INFO 0 +#define TYPE_PI_TRANSFORM 24 +#define TYPE_RHO_TRANSFORM 48 + +uint8_t getConstant(uint8_t type, uint8_t index) { + return constants[type + index]; + //return pgm_read_byte(&constants[type + index]); +} + +static uint64_t get_round_constant(uint8_t round) { + uint64_t result = 0; + + //uint8_t roundInfo = pgm_read_byte(&round_constant_info[round]); + uint8_t roundInfo = getConstant(TYPE_ROUND_INFO, round); + if (roundInfo & (1 << 6)) { result |= ((uint64_t)1 << 63); } + if (roundInfo & (1 << 5)) { result |= ((uint64_t)1 << 31); } + if (roundInfo & (1 << 4)) { result |= ((uint64_t)1 << 15); } + if (roundInfo & (1 << 3)) { result |= ((uint64_t)1 << 7); } + if (roundInfo & (1 << 2)) { result |= ((uint64_t)1 << 3); } + if (roundInfo & (1 << 1)) { result |= ((uint64_t)1 << 1); } + if (roundInfo & (1 << 0)) { result |= ((uint64_t)1 << 0); } + + return result; +} + + +/* Initializing a sha3 context for given number of output bits */ +void keccak_init(SHA3_CTX *ctx) { + /* NB: The Keccak capacity parameter = bits * 2 */ + + memset(ctx, 0, sizeof(SHA3_CTX)); +} + +/* Keccak theta() transformation */ +static void keccak_theta(uint64_t *A) { + uint64_t C[5], D[5]; + + for (uint8_t i = 0; i < 5; i++) { + C[i] = A[i]; + for (uint8_t j = 5; j < 25; j += 5) { C[i] ^= A[i + j]; } + } + + for (uint8_t i = 0; i < 5; i++) { + D[i] = ROTL64(C[(i + 1) % 5], 1) ^ C[(i + 4) % 5]; + } + + for (uint8_t i = 0; i < 5; i++) { + //for (uint8_t j = 0; j < 25; j += 5) { + for (uint8_t j = 0; j < 25; j += 5) { A[i + j] ^= D[i]; } + } +} + + +/* Keccak pi() transformation */ +static void keccak_pi(uint64_t *A) { + uint64_t A1 = A[1]; + //for (uint8_t i = 1; i < sizeof(pi_transform); i++) { + for (uint8_t i = 1; i < 24; i++) { + //A[pgm_read_byte(&pi_transform[i - 1])] = A[pgm_read_byte(&pi_transform[i])]; + A[getConstant(TYPE_PI_TRANSFORM, i - 1)] = A[getConstant(TYPE_PI_TRANSFORM, i)]; + } + A[10] = A1; + /* note: A[ 0] is left as is */ +} + +/* +ketch uses 30084 bytes (93%) of program storage space. Maximum is 32256 bytes. +Global variables use 743 bytes (36%) of dynamic memory, leaving 1305 bytes for local variables. Maximum is 2048 bytes. + +*/ +/* Keccak chi() transformation */ +static void keccak_chi(uint64_t *A) { + for (uint8_t i = 0; i < 25; i += 5) { + uint64_t A0 = A[0 + i], A1 = A[1 + i]; + A[0 + i] ^= ~A1 & A[2 + i]; + A[1 + i] ^= ~A[2 + i] & A[3 + i]; + A[2 + i] ^= ~A[3 + i] & A[4 + i]; + A[3 + i] ^= ~A[4 + i] & A0; + A[4 + i] ^= ~A0 & A1; + } +} + + +static void sha3_permutation(uint64_t *state) { + //for (uint8_t round = 0; round < sizeof(round_constant_info); round++) { + for (uint8_t round = 0; round < 24; round++) { + keccak_theta(state); + + /* apply Keccak rho() transformation */ + for (uint8_t i = 1; i < 25; i++) { + //state[i] = ROTL64(state[i], pgm_read_byte(&rhoTransforms[i - 1])); + state[i] = ROTL64(state[i], getConstant(TYPE_RHO_TRANSFORM, i - 1)); + } + + keccak_pi(state); + keccak_chi(state); + + /* apply iota(state, round) */ + *state ^= get_round_constant(round); + } +} + +/** + * The core transformation. Process the specified block of data. + * + * @param hash the algorithm state + * @param block the message block to process + * @param block_size the size of the processed block in bytes + */ +static void sha3_process_block(uint64_t hash[25], const uint64_t *block) { + for (uint8_t i = 0; i < 17; i++) { + hash[i] ^= le2me_64(block[i]); + } + + /* make a permutation of the hash */ + sha3_permutation(hash); +} + +//#define SHA3_FINALIZED 0x80000000 +//#define SHA3_FINALIZED 0x8000 + +/** + * Calculate message hash. + * Can be called repeatedly with chunks of the message to be hashed. + * + * @param ctx the algorithm context containing current hashing state + * @param msg message chunk + * @param size length of the message chunk + */ +void keccak_update(SHA3_CTX *ctx, const unsigned char *msg, uint16_t size) +{ + uint16_t idx = (uint16_t)ctx->rest; + + //if (ctx->rest & SHA3_FINALIZED) return; /* too late for additional input */ + ctx->rest = (unsigned)((ctx->rest + size) % BLOCK_SIZE); + + /* fill partial block */ + if (idx) { + uint16_t left = BLOCK_SIZE - idx; + memcpy((char*)ctx->message + idx, msg, (size < left ? size : left)); + if (size < left) return; + + /* process partial block */ + sha3_process_block(ctx->hash, ctx->message); + msg += left; + size -= left; + } + + while (size >= BLOCK_SIZE) { + uint64_t* aligned_message_block; + if (IS_ALIGNED_64(msg)) { + // the most common case is processing of an already aligned message without copying it + aligned_message_block = (uint64_t*)(void*)msg; + } else { + memcpy(ctx->message, msg, BLOCK_SIZE); + aligned_message_block = ctx->message; + } + + sha3_process_block(ctx->hash, aligned_message_block); + msg += BLOCK_SIZE; + size -= BLOCK_SIZE; + } + + if (size) { + memcpy(ctx->message, msg, size); /* save leftovers */ + } +} + +/** +* Store calculated hash into the given array. +* +* @param ctx the algorithm context containing current hashing state +* @param result calculated hash in binary form +*/ +void keccak_final(SHA3_CTX *ctx, unsigned char* result) +{ + uint16_t digest_length = 100 - BLOCK_SIZE / 2; + +// if (!(ctx->rest & SHA3_FINALIZED)) { + /* clear the rest of the data queue */ + memset((char*)ctx->message + ctx->rest, 0, BLOCK_SIZE - ctx->rest); + ((char*)ctx->message)[ctx->rest] |= 0x01; + ((char*)ctx->message)[BLOCK_SIZE - 1] |= 0x80; + + /* process final block */ + sha3_process_block(ctx->hash, ctx->message); +// ctx->rest = SHA3_FINALIZED; /* mark context as finalized */ +// } + + if (result) { + me64_to_le_str(result, ctx->hash, digest_length); + } +} + diff --git a/libraries/chain/machine.cpp b/libraries/chain/machine.cpp deleted file mode 100644 index 0f474e11..00000000 --- a/libraries/chain/machine.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "xgt/chain/machine.hpp" - -namespace xgt { namespace chain { - namespace detail { - class machine_impl { - public: - machine_impl( machine& self, machine_context ctx, std::vector code ) - : _self(self), ctx(ctx), code(code), pc(0), state(machine_state::running) - { - - } - - void step() - { - } - - machine& _self; - machine_context ctx; - std::vector code; - machine_address pc; - std::deque stack; - machine_state state; - }; - } - - machine::machine( machine_context ctx, std::vector code ) - : my ( new detail::machine_impl(*this, ctx, code) ) - { - - } - - machine::~machine() - { - } - - void machine::step() - { - my->step(); - } -} } // xgt::chain diff --git a/libraries/chain/xgt_evaluator.cpp b/libraries/chain/xgt_evaluator.cpp index 03dae1ce..5b280930 100644 --- a/libraries/chain/xgt_evaluator.cpp +++ b/libraries/chain/xgt_evaluator.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -9,12 +10,27 @@ #include #include #include -#include + +#include +#include +#include +#include #include #include #include +#include +#include +#include +#include "rlpvalue/include/rlpvalue.h" +#include "rlpvalue/include/rlpvalue.h" +#include "rlpvalue/lib/rlpvalue.cpp" +#include "rlpvalue/lib/rlpvalue_get.cpp" +#include "rlpvalue/lib/rlpvalue_write.cpp" +#include "rlpvalue/test/utilstrencodings.cpp" + +#include #ifndef IS_LOW_MEM #pragma GCC diagnostic push @@ -29,6 +45,7 @@ #include using boost::locale::conv::utf_to_utf; +using uint256_t = boost::multiprecision::uint256_t; std::wstring utf8_to_wstring(const std::string& str) { @@ -134,14 +151,16 @@ void verify_authority_accounts_exist( } void initialize_wallet_object( wallet_object& acc, const wallet_name_type& name, const public_key_type& key, - const dynamic_global_property_object& props, bool mined, const wallet_name_type& recovery_account, uint32_t hardfork ) + const dynamic_global_property_object& props, bool mined, const wallet_name_type& recovery_account, uint32_t hardfork, uint32_t nonce, std::string en_address = "" ) { wlog("?????? initialize_wallet_object name ${n}", ("n", name)); wlog("?????? initialize_wallet_object key ${n}", ("n", key)); wlog("?????? initialize_wallet_object created ${n}", ("n", props.time)); acc.name = name; + acc.en_address = en_address == "" ? fc::ripemd160::hex_digest(name) : en_address; acc.memo_key = key; acc.created = props.time; + acc.nonce = nonce; //acc.energybar.last_update_time = props.time.sec_since_epoch(); //acc.mined = mined; @@ -191,7 +210,7 @@ void wallet_create_evaluator::do_apply( const wallet_create_operation& o ) _db.create< wallet_object >( [&]( wallet_object& acc ) { - initialize_wallet_object( acc, wallet_name, o.memo_key, props, false /*mined*/, o.creator, _db.get_hardfork() ); + initialize_wallet_object( acc, wallet_name, o.memo_key, props, false /*mined*/, o.creator, _db.get_hardfork(), 0 ); }); _db.create< account_authority_object >( [&]( account_authority_object& auth ) @@ -200,6 +219,7 @@ void wallet_create_evaluator::do_apply( const wallet_create_operation& o ) auth.recovery = o.recovery; auth.money = o.money; auth.social = o.social; + auth.en_address = fc::ripemd160::hex_digest(wallet_name); auth.last_recovery_update = fc::time_point_sec::min(); }); } @@ -224,7 +244,7 @@ void wallet_update_evaluator::do_apply( const wallet_update_operation& o ) const auto& props = _db.get_dynamic_global_properties(); _db.create< wallet_object >( [&]( wallet_object& acc ) { - initialize_wallet_object( acc, o.wallet, *o.memo_key, props, false /*mined*/, XGT_INIT_MINER_NAME, _db.get_hardfork() ); + initialize_wallet_object( acc, o.wallet, *o.memo_key, props, false /*mined*/, XGT_INIT_MINER_NAME, _db.get_hardfork(), 0 ); }); _db.create< account_authority_object >( [&]( account_authority_object& auth ) @@ -714,7 +734,7 @@ void transfer_evaluator::do_apply( const transfer_operation& o ) _db.create< wallet_object >( [&]( wallet_object& w ) { - initialize_wallet_object( w, o.to, memo_pubkey, props, false /*mined*/, XGT_INIT_MINER_NAME, _db.get_hardfork() ); + initialize_wallet_object( w, o.to, memo_pubkey, props, false /*mined*/, XGT_INIT_MINER_NAME, _db.get_hardfork(), 0 ); }); _db.create< account_authority_object >( [&]( account_authority_object& auth ) @@ -925,6 +945,7 @@ void pow_evaluator::do_apply( const pow_operation& o ) const auto& dgp = db.get_dynamic_global_properties(); uint32_t target_pow = db.get_pow_summary_target(); + // TODO: May need a check to verify it is sha2_pow before continuing const auto& work = o.work.get< sha2_pow >(); fc::optional previous_block_id = db.previous_block_id(); if (previous_block_id.valid()) @@ -965,7 +986,7 @@ void pow_evaluator::do_apply( const pow_operation& o ) db.create< wallet_object >( [&]( wallet_object& acc ) { - initialize_wallet_object( acc, worker_account, *o.new_recovery_key, dgp, true /*mined*/, wallet_name_type(), _db.get_hardfork() ); + initialize_wallet_object( acc, worker_account, *o.new_recovery_key, dgp, true /*mined*/, wallet_name_type(), _db.get_hardfork(), 0 ); // ^ empty recovery account parameter means highest voted witness at time of recovery }); @@ -1007,8 +1028,164 @@ void report_over_production_evaluator::do_apply( const report_over_production_op { } +fc::ripemd160 make_contract_hash(const wallet_name_type& owner, const vector code) +{ + string s(code.begin(), code.end()); + string s2 = owner; + string s3(s2 + s); + return fc::ripemd160::hash(s3); +} + +// Forward declaration +machine::chain_adapter make_chain_adapter(chain::database& _db, wallet_name_type owner, wallet_name_type caller, wallet_name_type contract_wallet, contract_hash_type contract_hash, map& storage); + +std::map< uint64_t, std::function > energy_cost { + // [] == scoped variables, () == params, -> optional return type, {} == function body + {machine::stop_opcode, [](machine::machine& m){ return 0; }}, + {machine::add_opcode, [](machine::machine& m){ return 3; }}, + {machine::mul_opcode, [](machine::machine& m){ return 5; }}, + {machine::sub_opcode, [](machine::machine& m){ return 3; }}, + {machine::div_opcode, [](machine::machine& m){ return 5; }}, + {machine::sdiv_opcode, [](machine::machine& m){ return 5; }}, + {machine::mod_opcode, [](machine::machine& m){ return 5; }}, + {machine::smod_opcode, [](machine::machine& m){ return 5; }}, + {machine::addmod_opcode, [](machine::machine& m){ return 8; }}, + {machine::mulmod_opcode, [](machine::machine& m){ return 8; }}, + {machine::exp_opcode, [](machine::machine& m){ return 0; }}, // TODO -- Exp -- variable + {machine::signextend_opcode, [](machine::machine& m){ return 5; }}, + {machine::lt_opcode, [](machine::machine& m){ return 3; }}, + {machine::gt_opcode, [](machine::machine& m){ return 3; }}, + {machine::slt_opcode, [](machine::machine& m){ return 3; }}, + {machine::sgt_opcode, [](machine::machine& m){ return 3; }}, + {machine::eq_opcode, [](machine::machine& m){ return 3; }}, + {machine::iszero_opcode, [](machine::machine& m){ return 3; }}, + {machine::and_opcode, [](machine::machine& m){ return 3; }}, + {machine::or_opcode, [](machine::machine& m){ return 3; }}, + {machine::xor_opcode, [](machine::machine& m){ return 3; }}, + {machine::not_opcode, [](machine::machine& m){ return 3; }}, + {machine::byte_opcode, [](machine::machine& m){ return 3; }}, + {machine::shl_opcode, [](machine::machine& m){ return 3; }}, + {machine::shr_opcode, [](machine::machine& m){ return 3; }}, + {machine::sar_opcode, [](machine::machine& m){ return 3; }}, + {machine::sha3_opcode, [](machine::machine& m){ return 0; }}, // TODO -- SHA3 -- variable + {machine::address_opcode, [](machine::machine& m){ return 2; }}, + {machine::balance_opcode, [](machine::machine& m){ return 700; }}, + {machine::origin_opcode, [](machine::machine& m){ return 2; }}, + {machine::caller_opcode, [](machine::machine& m){ return 2; }}, + {machine::callvalue_opcode, [](machine::machine& m){ return 2; }}, + {machine::calldataload_opcode, [](machine::machine& m){ return 3; }}, + {machine::calldatasize_opcode, [](machine::machine& m){ return 2; }}, + {machine::calldatacopy_opcode, [](machine::machine& m){ return 0; }}, // TODO -- calldatacoy -- variab; le + {machine::codesize_opcode, [](machine::machine& m){ return 2; }}, + {machine::codecopy_opcode, [](machine::machine& m){ return 0; }}, // TODO -- codecopy -- variab; le + {machine::energyprice_opcode, [](machine::machine& m){ return 2; }}, + {machine::extcodesize_opcode, [](machine::machine& m){ return 700; }}, + {machine::extcodecopy_opcode, [](machine::machine& m){ return 0; }}, // TODO -- extcodecopy -- variab; le + {machine::returndatasize_opcode, [](machine::machine& m){ return 2; }}, + {machine::returndatacopy_opcode, [](machine::machine& m){ return 0; }}, // TODO -- returndatacopy -- variab; le + {machine::extcodehash_opcode, [](machine::machine& m){ return 700; }}, + {machine::blockhash_opcode, [](machine::machine& m){ return 20; }}, + {machine::coinbase_opcode, [](machine::machine& m){ return 2; }}, + {machine::timestamp_opcode, [](machine::machine& m){ return 2; }}, + {machine::number_opcode, [](machine::machine& m){ return 2; }}, + {machine::difficulty_opcode, [](machine::machine& m){ return 2; }}, + {machine::energylimit_opcode, [](machine::machine& m){ return 2; }}, + {machine::selfbalance_opcode, [](machine::machine& m){ return 0; }}, // TODO not yet implemented + {machine::pop_opcode, [](machine::machine& m){ return 3; }}, + {machine::mload_opcode, [](machine::machine& m){ return 3; }}, + {machine::mstore_opcode, [](machine::machine& m){ return 3; }}, + {machine::mstore8_opcode, [](machine::machine& m){ return 3; }}, + {machine::sload_opcode, [](machine::machine& m){ return 800; }}, + {machine::sstore_opcode, [](machine::machine& m){ return 0; }}, // TODO -- sstore -- variab; le + {machine::jump_opcode, [](machine::machine& m){ return 8; }}, + {machine::jumpi_opcode, [](machine::machine& m){ return 10; }}, + {machine::pc_opcode, [](machine::machine& m){ return 2; }}, + {machine::msize_opcode, [](machine::machine& m){ return 2; }}, + {machine::energy_opcode, [](machine::machine& m){ return 2; }}, + {machine::jumpdest_opcode, [](machine::machine& m){ return 1; }}, + {machine::push1_opcode, [](machine::machine& m){ return 3; }}, + {machine::push2_opcode, [](machine::machine& m){ return 3; }}, + {machine::push3_opcode, [](machine::machine& m){ return 3; }}, + {machine::push4_opcode, [](machine::machine& m){ return 3; }}, + {machine::push5_opcode, [](machine::machine& m){ return 3; }}, + {machine::push6_opcode, [](machine::machine& m){ return 3; }}, + {machine::push7_opcode, [](machine::machine& m){ return 3; }}, + {machine::push8_opcode, [](machine::machine& m){ return 3; }}, + {machine::push9_opcode, [](machine::machine& m){ return 3; }}, + {machine::push10_opcode, [](machine::machine& m){ return 3; }}, + {machine::push11_opcode, [](machine::machine& m){ return 3; }}, + {machine::push12_opcode, [](machine::machine& m){ return 3; }}, + {machine::push13_opcode, [](machine::machine& m){ return 3; }}, + {machine::push14_opcode, [](machine::machine& m){ return 3; }}, + {machine::push15_opcode, [](machine::machine& m){ return 3; }}, + {machine::push16_opcode, [](machine::machine& m){ return 3; }}, + {machine::push17_opcode, [](machine::machine& m){ return 3; }}, + {machine::push18_opcode, [](machine::machine& m){ return 3; }}, + {machine::push19_opcode, [](machine::machine& m){ return 3; }}, + {machine::push20_opcode, [](machine::machine& m){ return 3; }}, + {machine::push21_opcode, [](machine::machine& m){ return 3; }}, + {machine::push22_opcode, [](machine::machine& m){ return 3; }}, + {machine::push23_opcode, [](machine::machine& m){ return 3; }}, + {machine::push24_opcode, [](machine::machine& m){ return 3; }}, + {machine::push25_opcode, [](machine::machine& m){ return 3; }}, + {machine::push26_opcode, [](machine::machine& m){ return 3; }}, + {machine::push27_opcode, [](machine::machine& m){ return 3; }}, + {machine::push28_opcode, [](machine::machine& m){ return 3; }}, + {machine::push29_opcode, [](machine::machine& m){ return 3; }}, + {machine::push30_opcode, [](machine::machine& m){ return 3; }}, + {machine::push31_opcode, [](machine::machine& m){ return 3; }}, + {machine::push32_opcode, [](machine::machine& m){ return 3; }}, + {machine::dup1_opcode, [](machine::machine& m){ return 3; }}, + {machine::dup2_opcode, [](machine::machine& m){ return 3; }}, + {machine::dup3_opcode, [](machine::machine& m){ return 3; }}, + {machine::dup4_opcode, [](machine::machine& m){ return 3; }}, + {machine::dup5_opcode, [](machine::machine& m){ return 3; }}, + {machine::dup6_opcode, [](machine::machine& m){ return 3; }}, + {machine::dup7_opcode, [](machine::machine& m){ return 3; }}, + {machine::dup8_opcode, [](machine::machine& m){ return 3; }}, + {machine::dup9_opcode, [](machine::machine& m){ return 3; }}, + {machine::dup10_opcode, [](machine::machine& m){ return 3; }}, + {machine::dup11_opcode, [](machine::machine& m){ return 3; }}, + {machine::dup12_opcode, [](machine::machine& m){ return 3; }}, + {machine::dup13_opcode, [](machine::machine& m){ return 3; }}, + {machine::dup14_opcode, [](machine::machine& m){ return 3; }}, + {machine::dup15_opcode, [](machine::machine& m){ return 3; }}, + {machine::dup16_opcode, [](machine::machine& m){ return 3; }}, + {machine::swap1_opcode, [](machine::machine& m){ return 3; }}, + {machine::swap2_opcode, [](machine::machine& m){ return 3; }}, + {machine::swap3_opcode, [](machine::machine& m){ return 3; }}, + {machine::swap4_opcode, [](machine::machine& m){ return 3; }}, + {machine::swap5_opcode, [](machine::machine& m){ return 3; }}, + {machine::swap6_opcode, [](machine::machine& m){ return 3; }}, + {machine::swap7_opcode, [](machine::machine& m){ return 3; }}, + {machine::swap8_opcode, [](machine::machine& m){ return 3; }}, + {machine::swap9_opcode, [](machine::machine& m){ return 3; }}, + {machine::swap10_opcode, [](machine::machine& m){ return 3; }}, + {machine::swap11_opcode, [](machine::machine& m){ return 3; }}, + {machine::swap12_opcode, [](machine::machine& m){ return 3; }}, + {machine::swap13_opcode, [](machine::machine& m){ return 3; }}, + {machine::swap14_opcode, [](machine::machine& m){ return 3; }}, + {machine::swap15_opcode, [](machine::machine& m){ return 3; }}, + {machine::swap16_opcode, [](machine::machine& m){ return 3; }}, + {machine::log0_opcode, [](machine::machine& m){ return 0; }}, // TODO -- log0 -- variable + {machine::log1_opcode, [](machine::machine& m){ return 0; }}, // TODO -- log1 -- variable + {machine::log2_opcode, [](machine::machine& m){ return 0; }}, // TODO -- log2 -- variable + {machine::log3_opcode, [](machine::machine& m){ return 0; }}, // TODO -- log3 -- variable + {machine::log4_opcode, [](machine::machine& m){ return 0; }}, // TODO -- log4 -- variable + {machine::create_opcode, [](machine::machine& m){ return 0; }}, // TODO -- create -- variable + {machine::call_opcode, [](machine::machine& m){ return 0; }}, // TODO -- call -- variable + {machine::callcode_opcode, [](machine::machine& m){ return 0; }}, // TODO -- callcode -- variable + {machine::return_opcode, [](machine::machine& m){ return 0; }}, + {machine::delegatecall_opcode, [](machine::machine& m){ return 0; }}, // TODO -- delegatecall -- variable + {machine::create2_opcode, [](machine::machine& m){ return 0; }}, // TODO -- create2 -- variable + {machine::staticcall_opcode, [](machine::machine& m){ return 0; }}, // TODO -- staticcall -- variable + {machine::revert_opcode, [](machine::machine& m){ return 0; }}, + {machine::invalid_opcode, [](machine::machine& m){ return 0; }}, + {machine::selfdestruct_opcode, [](machine::machine& m){ return 0; }} // TODO -- selfdestruct -- variable +}; + // TODO: Revisit this -fc::ripemd160 generate_random_ripmd160() +fc::ripemd160 generate_random_ripemd160() { const size_t buflen = 128; char buf[buflen]; @@ -1016,42 +1193,948 @@ fc::ripemd160 generate_random_ripmd160() return fc::ripemd160::hash(buf, buflen); } +uint256_t ripemd160_to_uint256_t(fc::ripemd160 h) +{ + uint256_t n(0); + uint256_t m; + for (int i = 0; i < 5; i++) + { + m = h._hash[i]; + m = m << (8 * i); + n |= m; + } + return n; +} + +en_address_type uint256_t_to_ripemd160(uint256_t address) { + std::stringstream ss; + ss << std::hex << address; + return ss.str(); +} + +int char2int(char input) +{ + if(input >= '0' && input <= '9') + return input - '0'; + if(input >= 'A' && input <= 'F') + return input - 'A' + 10; + if(input >= 'a' && input <= 'f') + return input - 'a' + 10; + throw std::invalid_argument("Invalid input string"); +} + +// This function assumes src to be a zero terminated sanitized string with +// an even number of [0-9a-f] characters, and target to be sufficiently large +void hex2bin(const char* src, char* target) +{ + while(*src && src[1]) + { + *(target++) = char2int(*src)*16 + char2int(src[1]); + src += 2; + } +} + +template +inline std::string to_hex(const Hash& h) +{ + static const auto hex_chars = "0123456789abcdef"; + std::string str; + str.reserve(sizeof(h) * 2); + for (auto b : h.bytes) + { + str.push_back(hex_chars[uint8_t(b) >> 4]); + str.push_back(hex_chars[uint8_t(b) & 0xf]); + } + return str; +} + +void hex_to_uint8(std::string hex, uint8_t bytes[]) { + if ( hex.size() >= 2 && hex[0] == '0' && (hex[1] == 'x' || hex[1] == 'X') ) + hex.erase(0, 2); + if (hex.size() % 2 != 0) + hex = '0' + hex; + for (size_t i = 0; i < hex.size(); i += 2) { + if (hex.substr(i, 2) == "0x") + continue; + uint8_t code = std::stoi(hex.substr(i, 2), 0, 16); + bytes[i / 2] = code; + } + return; +} + +std::string generate_create2_address(std::string sender, std::string salt, std::string init_code, std::string target_address = "TODO MIGRATE TO TESTS") { + std::stringstream ss; + + // Recipe: keccak256( 0xff ++ address ++ salt ++ keccak256(init_code))[12:] + + size_t init_code_size = init_code.size() / 2; + uint8_t init_code_bytes[init_code_size]; + hex_to_uint8(init_code, init_code_bytes); + auto init_code_output = ethash_keccak256( init_code_bytes, init_code_size ); + std::string init_code_hash = to_hex(init_code_output); + + ss << "ff" << sender << salt << init_code_hash; + std::string keccak_input_str = ss.str(); + + size_t size = keccak_input_str.size() / 2; + uint8_t bytes[size]; + hex_to_uint8(keccak_input_str, bytes); + + auto keccak_output = ethash_keccak256( bytes, size ); + std::string untrimmed_address = to_hex(keccak_output); + std::string generated_create2_address = untrimmed_address.substr(24, 40); + + return generated_create2_address; +} + +// TODO sender is en_address +const std::string generate_en_address(std::string sender, uint32_t nonce, std::string salt = "", std::vector init_code = {}) { + if (salt == "") { + std::string rlp_input; + rlp_input += sender += nonce; + + RLPValue v = RLPValue(rlp_input); + + // Generate output rlp-encoded hex + std::string genOutput = v.write(); + std::string genHexStr = HexStr( genOutput.begin(), genOutput.end() ); + + size_t size = genHexStr.size() / 2; + uint8_t bytes[size]; + hex_to_uint8(genHexStr, bytes); + + auto keccak_output = ethash_keccak256( bytes, size ); + std::string untrimmed_address = to_hex(keccak_output); + std::string generated_rlp_address = untrimmed_address.substr(untrimmed_address.size() - 40); + + return generated_rlp_address; + } else { + std::stringstream ss; + + // TODO migrate to tests + // generate_create2_address("0000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "00", "4d1a2e2bb4f88f0250f26ffff098b0b30b26bf38"); + // generate_create2_address("deadbeef00000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "00", "b928f69bb1d91cd65274e3c79d8986362984fda3"); + // generate_create2_address("deadbeef00000000000000000000000000000000", "000000000000000000000000feed000000000000000000000000000000000000", "00", "d04116cdd17bebe565eb2422f2497e06cc1c9833"); + // generate_create2_address("0000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "deadbeef", "70f2b2914a2a4b783faefb75f459a580616fcb5e"); + // generate_create2_address("00000000000000000000000000000000deadbeef", "00000000000000000000000000000000000000000000000000000000cafebabe", "deadbeef", "60f3f640a8508fc6a86d45Df051962668e1e8ac7"); + // generate_create2_address("00000000000000000000000000000000deadbeef", "00000000000000000000000000000000000000000000000000000000cafebabe", "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "1d8bfdc5d46dc4f61d6b6115972536ebe6a8854c"); + // generate_create2_address("0000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "", "e33c0c7f7df4809055c3eba6c09cfe4baf1bd9e0"); + + for (size_t i = 0; i < init_code.size(); i++) { + ss << std::hex << (machine::opcode)init_code[i]; + } + + std::string init_code_str = ss.str(); + std::string trimmed_wallet_name = generate_create2_address(sender, salt, init_code_str); + + return trimmed_wallet_name; + } +}; + +const wallet_object& wallet_create(chain::database& _db, uint32_t nonce, std::string predetermined_en_wallet_name = "") +{ + fc::ecc::private_key recovery_privkey = generate_random_private_key(); + fc::ecc::public_key recovery_pubkey = recovery_privkey.get_public_key(); + fc::ecc::private_key money_privkey = generate_random_private_key(); + fc::ecc::public_key money_pubkey = money_privkey.get_public_key(); + fc::ecc::private_key social_privkey = generate_random_private_key(); + fc::ecc::public_key social_pubkey = social_privkey.get_public_key(); + fc::ecc::private_key memo_privkey = generate_random_private_key(); + fc::ecc::public_key memo_pubkey = memo_privkey.get_public_key(); + std::vector recovery_pubkeys = {recovery_pubkey}; + const auto& props = _db.get_dynamic_global_properties(); + + std::string wallet_name = wallet_create_operation::get_wallet_name(recovery_pubkeys); + + // TODO Add en name to wallet create operation + const wallet_object& wallet = _db.create< wallet_object >( [&]( wallet_object& w ) + { + initialize_wallet_object( w, wallet_name, memo_pubkey, props, false /*mined*/, XGT_INIT_MINER_NAME, _db.get_hardfork(), nonce, predetermined_en_wallet_name ); + }); + + _db.create< account_authority_object >( [&]( account_authority_object& auth ) + { + auth.account = wallet_name; + auth.recovery.weight_threshold = 1; + auth.recovery.add_authority((public_key_type)recovery_pubkey, 1); + auth.money.weight_threshold = 1; + auth.money.add_authority((public_key_type)money_pubkey, 1); + auth.social.weight_threshold = 1; + auth.social.add_authority((public_key_type)social_pubkey, 1); + auth.last_recovery_update = fc::time_point_sec::min(); + }); + + return wallet; +} + +std::vector contract_invoke(chain::database& _db, wallet_name_type o, wallet_name_type caller, contract_hash_type contract_hash, uint64_t value, uint64_t energy, std::vector args, map< fc::sha256, fc::sha256 >& storage) +{ + wlog("contract_invoke another contract ${w}", ("w",contract_hash)); + + std::stringstream ss; + const auto& c = _db.get_contract(contract_hash); + const wallet_object& destination_wallet = _db.get_account(c.wallet); + + ss << std::hex << std::string(destination_wallet.en_address); + uint256_t destination_en_address; + ss >> destination_en_address; + ss.str(""); + + const wallet_object& wallet = _db.get_account(caller); + + ss << std::hex << std::string(wallet.en_address); + uint256_t caller_en_address; + ss >> caller_en_address; + ss.str(""); + + machine::message msg = { + 0, + 0, + int64_t(energy), + caller_en_address, + destination_en_address, + value, + // TODO args size is inaccurate + args.size() * 2, + args, + 0 + }; + + const bool is_debug = true; + const uint64_t block_timestamp = static_cast( _db.head_block_time().sec_since_epoch() ); + const uint64_t block_number = _db.head_block_num(); + const uint64_t block_difficulty = static_cast( _db.get_pow_summary_target() ); + const uint64_t block_energylimit = 0; + const uint64_t tx_energyprice = 0; + const uint256_t tx_origin = caller_en_address; // TODO update this + const uint256_t block_coinbase = caller_en_address; // TODO update this to this block's miner + + machine::context ctx = { + is_debug, + block_timestamp, + block_number, + block_difficulty, + block_energylimit, + tx_energyprice, + tx_origin, + block_coinbase + }; + + int64_t energy_cost_incurred = 0; + + std::vector code(c.code.begin(), c.code.end()); + machine::chain_adapter adapter = make_chain_adapter(_db, o, caller, c.wallet, contract_hash, storage); + machine::machine m(ctx, code, msg, adapter); + + std::string line; + while (m.is_running()) + { + std::cerr << "step\n" << std::endl; + std::cerr << m.to_json() << std::endl; + m.step(); + auto energy_callback = energy_cost[m.get_current_opcode()]; + // Calculate energy cost and add to total + energy_cost_incurred += energy_callback(m); + // Print out any logging that was generated + while ( std::getline(m.get_logger(), line) ) + std::cerr << "\e[36m" << "LOG: " << line << "\e[0m" << std::endl; + } + while ( std::getline(m.get_logger(), line) ) + std::cerr << "\e[36m" << "LOG: " << line << "\e[0m" << std::endl; + std::cout << m.to_json() << std::endl; + + uint32_t energy_regen_period = XGT_ENERGY_REGENERATION_SECONDS; // TODO: Hardcode this for now (should be a constant I think) + _db.modify(wallet, [&](wallet_object& w) + { + util::update_energybar( _db.get_dynamic_global_properties(), w, energy_regen_period, true ); + w.energybar.use_energy( energy_cost_incurred ); + }); + + // Transfer value (C_xfer) if callvalue != 0 + // TODO XXX Value is dramatically adjusted for test purposes... + // Ethereum wei values are significantly smaller proportionally than XGT g values + // 1 Ether = 1,000,000,000,000,000,000 wei + // 1 XGT = 100,000,000 g + if (value != 0) { + auto callvalue = asset( value / 1000000000, XGT_SYMBOL ); + + const auto& contract_wallet = _db.get_account(c.wallet); + + _db.adjust_balance( contract_wallet, callvalue ); + + const auto& caller_wallet = _db.get_account(caller); + + _db.adjust_balance( caller_wallet, -callvalue ); + } + + wlog("contract_invoke return value ${w}", ("w",m.get_return_value())); + return m.get_return_value(); +} + void contract_create_evaluator::do_apply( const contract_create_operation& op ) { - wlog("!!!!!! contract_create owner ${w} code size ${x}", ("w",op.owner)("x",op.code.size())); - _db.create< contract_object >( [&](contract_object& c) + wlog("!!!!!! contract_create owner ${w} code size ${y}", ("w",op.owner)("y",op.code.size())); + + const auto& contract_wallet = wallet_create(_db, 1); + + auto base_contract = _db.create< contract_object >( [&](contract_object& c) { - //c.contract_hash = generate_random_ripmd160(); + c.contract_hash = make_contract_hash(op.owner, op.code); + wlog("!!!!!! contract_create contract_hash ${c}", ("c",c.contract_hash)); + c.wallet = contract_wallet.name; c.owner = op.owner; c.code = op.code; }); + + auto storage = map< fc::sha256, fc::sha256 >(); + _db.create< contract_storage_object >([&](contract_storage_object& cs) { + cs.contract = base_contract.contract_hash; + cs.caller = op.owner; + cs.data = storage; + }); + + auto machine_return = contract_invoke(_db, op.owner, op.owner, base_contract.contract_hash, 0, 0, {}, storage); + std::vector result(machine_return.begin(), machine_return.end()); + + const contract_storage_object* cs = _db.find_contract_storage(base_contract.contract_hash, op.owner); + _db.modify< contract_storage_object >(*cs, [&](contract_storage_object& cs) { + cs.data = storage; + }); + + const auto& contract = _db.get_contract(base_contract.contract_hash); + _db.modify< contract_object >(contract, [&](contract_object& c) { + c.code = result; + }); +} + +std::string inspect(std::vector words) +{ + std::stringstream ss; + ss << "["; + for (size_t i = 0; i < words.size(); i++) + { + ss << std::to_string(words.at(i)); + if (i != words.size() -1) + ss << ", "; + } + ss << "]"; + return ss.str(); +} + +machine::chain_adapter make_chain_adapter(chain::database& _db, wallet_name_type owner, wallet_name_type caller, wallet_name_type contract_wallet, contract_hash_type contract_hash, map& storage) +{ + + std::function< machine::big_word(std::vector) > sha3 = [&](std::vector memory) -> machine::big_word + { + std::stringstream ss; + for (size_t i = 0; i < memory.size(); i++) { + ss << std::hex << (machine::opcode)memory[i]; + } + + std::string memory_str = ss.str(); + + size_t memory_size = memory_str.size() / 2; + uint8_t memory_bytes[memory_size]; + hex_to_uint8(memory_str, memory_bytes); + auto memory_output = ethash_keccak256( memory_bytes, memory_size ); + std::string memory_hash = to_hex(memory_output); + + ss.str(""); + ss << std::hex << memory_hash; + uint256_t sha3_return; + ss >> sha3_return; + + return sha3_return; + }; + + std::function< machine::big_word(machine::big_word) > get_balance = [&](machine::big_word en_address) -> machine::big_word + { + std::stringstream ss; + ss << std::hex << en_address; + const en_address_type r160 = ss.str(); + auto& wallet = _db.get_account_by_en_address(r160); + return static_cast(wallet.balance.amount.value); + }; + + std::function< machine::big_word(machine::big_word) > get_code_hash = [&](machine::big_word address) -> machine::big_word + { + // TODO XXX: convert to ethash keccak256 + std::stringstream ss; + ss << address; + const en_address_type& en_address = ss.str(); + const wallet_object& contract_wallet = _db.get_account_by_en_address(en_address); + const auto& contract = _db.get_contract_by_wallet(contract_wallet.name); + std::string message(contract.code.begin(), contract.code.end()); + unsigned char output[32]; + SHA3_CTX ctx; + keccak_init(&ctx); + keccak_update(&ctx, (unsigned char*)message.c_str(), message.size()); + keccak_final(&ctx, output); + std::string fin((char*)output, 32); + uint256_t x; + ss << std::hex << fin; + ss >> x; + return x; + }; + + // TODO: Revisit this, we may want to use the original sha256 hash + std::function< machine::big_word(uint64_t) > get_block_hash = [&](uint64_t block_num) -> machine::big_word + { + if ( block_num > _db.head_block_num() ) { + return 0; + } + fc::optional block_hash = _db.get_block_hash_from_block_num(block_num); + auto ripemd160_hash = fc::ripemd160::hash( block_hash->data() ); + machine::big_word item = ripemd160_to_uint256_t(ripemd160_hash); + return item; + }; + + std::function< std::vector(machine::big_word) > get_code_at_addr = [&](machine::big_word address) -> std::vector + { + std::stringstream ss; + ss << std::hex << address; + const en_address_type r160 = ss.str(); + const auto& contract_wallet_account = _db.get_account_by_en_address(r160); + const contract_object& contract = _db.get_contract_by_wallet(contract_wallet_account.name); + + return std::vector(contract.code.begin(), contract.code.end()); + }; + + std::function< machine::big_word(std::vector, machine::big_word) > contract_create = [&, owner, caller, contract_hash](std::vector memory, machine::big_word value) -> machine::big_word + { + std::stringstream ss; + + const wallet_name_type sender_address = _db.get_contract(contract_hash).wallet; + const auto& caller_contract_wallet = _db.get_account(sender_address); + + if (caller_contract_wallet.balance.amount.value >= value) { + fc::ripemd160 new_contract_hash = generate_random_ripemd160(); + + std::string new_wallet_name = generate_en_address(std::string(sender_address), caller_contract_wallet.nonce); + + wallet_create(_db, 1, new_wallet_name); + chain::contract_object base_contract = _db.create< contract_object >( [&](contract_object& c) { + c.contract_hash = new_contract_hash; + c.owner = sender_address; + c.code = reinterpret_cast< std::vector& >(memory); + c.wallet = new_wallet_name; + }); + + if (value != 0) { + // TODO XXX value is set to be compatible with eth value, needs to be adjusted + auto callvalue = asset( value, XGT_SYMBOL ); + _db.adjust_balance( caller_contract_wallet, -callvalue ); + _db.adjust_balance( base_contract.wallet, callvalue ); + } + + const contract_storage_object* cs = _db.find_contract_storage(new_contract_hash, sender_address); + + map< fc::sha256, fc::sha256 > storage; + if (cs != nullptr) { + storage = cs->data; + } + else { + storage = map< fc::sha256, fc::sha256 >(); + } + + _db.create< contract_storage_object >([&](contract_storage_object& cs) { + cs.contract = new_contract_hash; + cs.caller = sender_address; + cs.data = storage; + }); + + // TODO Exceptions should occupy return_value in the case of contract invoke failure (result == 0) + std::vector base_contract_return = contract_invoke(_db, owner, sender_address, new_contract_hash, 0, 0, {}, storage); + std::vector result(base_contract_return.begin(), base_contract_return.end()); + + cs = _db.find_contract_storage(new_contract_hash, sender_address); + _db.modify< contract_storage_object >(*cs, [&](contract_storage_object& cs) { + cs.data = storage; + }); + + const auto& deployed_contract = _db.get_contract(new_contract_hash); + _db.modify< contract_object >(deployed_contract, [&](contract_object& co) { + co.code = result; + }); + + const wallet_object& deployed_contract_wallet = _db.get_account(deployed_contract.wallet); + ss << std::hex << std::string(deployed_contract_wallet.en_address); + uint256_t new_contract_wallet_address; + ss >> new_contract_wallet_address; + + _db.modify( caller_contract_wallet, [&]( wallet_object& acc ) + { + if (acc.nonce) + acc.nonce += 1; + else + acc.nonce = 1; + }); + + return new_contract_wallet_address; + } + else { + return 0; + } + }; + + std::function< std::pair< machine::word, std::vector >(machine::big_word, uint64_t, machine::big_word, std::vector) > contract_call = [&, caller, contract_hash](machine::big_word address, uint64_t energy, machine::big_word value, std::vector args) -> std::pair< machine::word, std::vector > + { + // TODO Implement call depth limit + std::stringstream ss; + + const en_address_type r160 = uint256_t_to_ripemd160(address); + const wallet_object* ext_wallet = _db.find_account_by_en_address(r160); + wallet_name_type ext_wallet_name; + + if (ext_wallet != nullptr) { + ext_wallet_name = ext_wallet->name; + } else { + // TODO Check energy before creating contract + ss << std::hex << contract_create(args, value); + const en_address_type new_r160 = ss.str(); + const wallet_object* new_wallet = _db.find_account_by_en_address(new_r160); + ext_wallet_name = new_wallet->name; + } + + const wallet_name_type sender_address = _db.get_contract(contract_hash).wallet; + const auto& caller_contract_wallet = _db.get_account(sender_address); + + if (value != 0) { + if (caller_contract_wallet.balance.amount.value >= value) { + // TODO XXX value is set to be compatible with eth value, needs to be adjusted + auto callvalue = asset( value, XGT_SYMBOL ); + _db.adjust_balance( caller_contract_wallet, -callvalue ); + _db.adjust_balance( ext_wallet_name, callvalue ); + } else { + return std::make_pair(0, std::vector()); + } + } + const contract_object* ext_contract = _db.find_contract_by_wallet(ext_wallet_name); + + std::vector contract_return = {}; + + if (args.size() > 0) { + if (!ext_contract) { + const en_address_type new_contract_r160 = uint256_t_to_ripemd160( contract_create(args, 0) ); + const wallet_object* new_contract_wallet = _db.find_account_by_en_address(new_contract_r160); + ext_wallet_name = new_contract_wallet->name; + ext_contract = _db.find_contract_by_wallet(ext_wallet_name); + } + const contract_storage_object* cs = _db.find_contract_storage(ext_contract->contract_hash, owner); + map< fc::sha256, fc::sha256 > storage; + if (cs) + storage = cs->data; + else + storage = map< fc::sha256, fc::sha256 >(); + + contract_return = contract_invoke(_db, ext_contract->owner, sender_address, ext_contract->contract_hash, (uint64_t)value, energy, args, storage); + + if (cs != nullptr) { + _db.modify< contract_storage_object >(*cs, [&](contract_storage_object& cs) { + cs.contract = ext_contract->contract_hash; + cs.caller = caller; + cs.data = storage; + }); + } else { + _db.create< contract_storage_object >([&](contract_storage_object& cs) { + cs.contract = ext_contract->contract_hash; + cs.caller = caller; + cs.data = storage; + }); + } + } + return std::make_pair(machine::word(1), contract_return); + }; + + std::function< std::pair< machine::word, std::vector >(machine::big_word, uint64_t, machine::big_word, std::vector) > contract_callcode = [&, caller, contract_hash](machine::big_word address, uint64_t energy, machine::big_word value, std::vector args) -> std::pair< machine::word, std::vector > + { + // TODO Implement call depth limit + std::stringstream ss; + + const en_address_type r160 = uint256_t_to_ripemd160(address); + const wallet_object* ext_wallet = _db.find_account_by_en_address(r160); + wallet_name_type ext_wallet_name; + + if (ext_wallet != nullptr) { + ext_wallet_name = ext_wallet->name; + } else { + // TODO Check energy before creating contract + ss << std::hex << contract_create(args, value); + const en_address_type new_r160 = ss.str(); + const wallet_object* new_wallet = _db.find_account_by_en_address(new_r160); + ext_wallet_name = new_wallet->name; + } + + const auto& caller_wallet = _db.get_account(caller); + + if (value != 0) { + if (caller_wallet.balance.amount.value >= value) { + // TODO XXX value is set to be compatible with eth value, needs to be adjusted + auto callvalue = asset( value, XGT_SYMBOL ); + _db.adjust_balance( caller, -callvalue ); + _db.adjust_balance( caller, callvalue ); + } else { + return std::make_pair(0, std::vector()); + } + } + const contract_object* ext_contract = _db.find_contract_by_wallet(ext_wallet_name); + + std::vector contract_return = {}; + + if (args.size() > 0) { + if (!ext_contract) { + const en_address_type new_contract_r160 = uint256_t_to_ripemd160( contract_create(args, 0) ); + const wallet_object* new_contract_wallet = _db.find_account_by_en_address(new_contract_r160); + ext_wallet_name = new_contract_wallet->name; + ext_contract = _db.find_contract_by_wallet(ext_wallet_name); + } + const contract_storage_object* cs = _db.find_contract_storage(contract_hash, caller); + map< fc::sha256, fc::sha256 > storage; + if (cs) + storage = cs->data; + else + storage = map< fc::sha256, fc::sha256 >(); + + contract_return = contract_invoke(_db, ext_contract->owner, caller, ext_contract->contract_hash, (uint64_t)value, energy, args, storage); + + if (cs != nullptr) { + _db.modify< contract_storage_object >(*cs, [&](contract_storage_object& cs) { + cs.contract = contract_hash; + cs.caller = caller; + cs.data = storage; + }); + } else { + _db.create< contract_storage_object >([&](contract_storage_object& cs) { + cs.contract = contract_hash; + cs.caller = caller; + cs.data = storage; + }); + } + } + return std::make_pair(machine::word(1), contract_return); + }; + + std::function< std::pair< machine::word, std::vector >(machine::big_word, uint64_t, std::vector) > contract_delegatecall = [&, caller, owner, contract_hash](machine::big_word address, uint64_t energy, std::vector args) -> std::pair< machine::word, std::vector > + { + // TODO Implement call depth limit + std::stringstream ss; + + const en_address_type r160 = uint256_t_to_ripemd160(address); + const wallet_object* ext_wallet = _db.find_account_by_en_address(r160); + wallet_name_type ext_wallet_name; + + if (ext_wallet != nullptr) { + ext_wallet_name = ext_wallet->name; + } else { + // TODO Check energy before creating contract + ss << std::hex << contract_create(args, 0); + const en_address_type new_r160 = ss.str(); + const wallet_object* new_wallet = _db.find_account_by_en_address(new_r160); + ext_wallet_name = new_wallet->name; + } + + const contract_object* ext_contract = _db.find_contract_by_wallet(ext_wallet_name); + + std::vector contract_return = {}; + + if (args.size() > 0) { + if (!ext_contract) { + const en_address_type new_contract_r160 = uint256_t_to_ripemd160( contract_create(args, 0) ); + const wallet_object* new_contract_wallet = _db.find_account_by_en_address(new_contract_r160); + ext_wallet_name = new_contract_wallet->name; + ext_contract = _db.find_contract_by_wallet(ext_wallet_name); + } + const contract_storage_object* cs = _db.find_contract_storage(contract_hash, caller); + map< fc::sha256, fc::sha256 > storage; + if (cs) + storage = cs->data; + else + storage = map< fc::sha256, fc::sha256 >(); + + contract_return = contract_invoke(_db, ext_contract->owner, caller, ext_contract->contract_hash, 0, energy, args, storage); + + if (cs != nullptr) { + _db.modify< contract_storage_object >(*cs, [&](contract_storage_object& cs) { + cs.contract = contract_hash; + cs.caller = caller; + cs.data = storage; + }); + } else { + _db.create< contract_storage_object >([&](contract_storage_object& cs) { + cs.contract = contract_hash; + cs.caller = caller; + cs.data = storage; + }); + } + } + return std::make_pair(machine::word(1), contract_return); + }; + + std::function< std::pair< machine::word, std::vector >(machine::big_word, uint64_t, std::vector) > contract_staticcall = [&, owner, caller, contract_hash](machine::big_word address, uint64_t energy, std::vector args) -> std::pair< machine::word, std::vector > + { + std::stringstream ss; + + const en_address_type r160 = uint256_t_to_ripemd160(address); + const wallet_object* ext_wallet = _db.find_account_by_en_address(r160); + wallet_name_type ext_wallet_name; + + if (ext_wallet != nullptr) { + ext_wallet_name = ext_wallet->name; + } else { + ss << std::hex << contract_create(args, 0); + const en_address_type new_r160 = ss.str(); + const wallet_object* new_wallet = _db.find_account_by_en_address(new_r160); + ext_wallet_name = new_wallet->name; + } + + const wallet_name_type sender_address = _db.get_contract(contract_hash).wallet; + const contract_object* ext_contract = _db.find_contract_by_wallet(ext_wallet_name); + + std::vector contract_return = {}; + + if (args.size() > 0) { + if (!ext_contract) { + const en_address_type new_contract_r160 = uint256_t_to_ripemd160( contract_create(args, 0) ); + const wallet_object* new_contract_wallet = _db.find_account_by_en_address(new_contract_r160); + ext_wallet_name = new_contract_wallet->name; + ext_contract = _db.find_contract_by_wallet(ext_wallet_name); + } + const contract_storage_object* cs = _db.find_contract_storage(ext_contract->contract_hash, owner); + map< fc::sha256, fc::sha256 > storage; + if (cs) + storage = cs->data; + else + storage = map< fc::sha256, fc::sha256 >(); + + contract_return = contract_invoke(_db, ext_contract->owner, sender_address, ext_contract->contract_hash, 0, energy, args, storage); + + if (cs != nullptr) { + _db.modify< contract_storage_object >(*cs, [&](contract_storage_object& cs) { + cs.contract = ext_contract->contract_hash; + cs.caller = caller; + cs.data = storage; + }); + } else { + _db.create< contract_storage_object >([&](contract_storage_object& cs) { + cs.contract = ext_contract->contract_hash; + cs.caller = caller; + cs.data = storage; + }); + } + } + return std::make_pair(machine::word(1), contract_return); + }; + + std::function< machine::big_word(std::vector, machine::big_word, machine::big_word) > contract_create2 = [&_db, owner, caller, contract_hash](std::vector memory, machine::big_word value, machine::big_word salt) -> machine::big_word + { + // TODO: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1014.md + const wallet_name_type sender_address = _db.get_contract(contract_hash).wallet; + const auto& caller_contract_wallet = _db.get_account(sender_address); + + // TODO XXX Create wallet for contract + + if (caller_contract_wallet.balance.amount.value >= value) { + fc::ripemd160 new_contract_hash = generate_random_ripemd160(); + + std::stringstream ss; + ss << salt; + std::string salt_str = ss.str(); + ss.str(""); + + std::string caller_en_address = caller_contract_wallet.en_address; + std::string new_wallet_en_address = generate_en_address(caller_en_address, caller_contract_wallet.nonce, salt_str, memory); + + wallet_create(_db, caller_contract_wallet.nonce, new_wallet_en_address); + + const auto& new_wallet_name = _db.get_account_by_en_address(new_wallet_en_address).name; + + chain::contract_object base_contract = _db.create< contract_object >( [&](contract_object& c) { + c.contract_hash = new_contract_hash; + c.owner = sender_address; + c.code = reinterpret_cast< std::vector& >(memory); + c.wallet = new_wallet_name; + }); + + if (value != 0) { + // TODO XXX value is set to be compatible with eth value, needs to be adjusted + auto callvalue = asset( value, XGT_SYMBOL ); + // TODO this should be the calling contract's wallet + _db.adjust_balance( caller_contract_wallet, -callvalue ); + _db.adjust_balance( base_contract.wallet, callvalue ); + } + + const contract_storage_object* cs = _db.find_contract_storage(new_contract_hash, sender_address); + + map< fc::sha256, fc::sha256 > storage; + if (cs != nullptr) { + storage = cs->data; + } + else { + storage = map< fc::sha256, fc::sha256 >(); + } + + _db.create< contract_storage_object >([&](contract_storage_object& cs) { + cs.contract = new_contract_hash; + cs.caller = sender_address; + cs.data = storage; + }); + + // TODO Exceptions should occupy return_value in the case of contract invoke failure (result == 0) + std::vector base_contract_return = contract_invoke(_db, owner, sender_address, new_contract_hash, 0, 0, {}, storage); + std::vector result(base_contract_return.begin(), base_contract_return.end()); + + cs = _db.find_contract_storage(new_contract_hash, sender_address); + _db.modify< contract_storage_object >(*cs, [&](contract_storage_object& cs) { + cs.data = storage; + }); + + const auto& deployed_contract = _db.get_contract(new_contract_hash); + _db.modify< contract_object >(deployed_contract, [&](contract_object& co) { + co.code = result; + }); + + const std::string& address_ref = std::string(new_wallet_en_address); + + ss.str(""); + ss << std::hex << address_ref; + uint256_t new_contract_wallet_address; + ss >> new_contract_wallet_address; + + _db.modify( caller_contract_wallet, [&]( wallet_object& acc ) + { + if (acc.nonce) + acc.nonce = acc.nonce + 1; + else + acc.nonce = 1; + }); + + return new_contract_wallet_address; + } + else { + return 0; + } + }; + + std::function< bool(std::vector) > revert = [&](std::vector memory) -> bool + { + // TODO from eth yellowpaper: Halt execution reverting state changes but returning data and remaining gas. + return true; + }; + + std::function< machine::big_word(machine::big_word) > get_storage = [&](uint256_t key) -> machine::big_word + { + return _db.hash_to_bigint( storage[ _db.bigint_to_hash(key) ] ); + }; + + std::function< bool(machine::big_word, machine::big_word) > set_storage = [&](machine::big_word key, machine::big_word value) -> bool + { + storage[ _db.bigint_to_hash(key) ] = _db.bigint_to_hash(value); + return true; + }; + + std::function< std::vector(std::vector) > contract_return = [&](std::vector memory) -> std::vector + { + return memory; + }; + + std::function< bool(machine::big_word) > self_destruct = [&](machine::big_word address) -> bool + { + // TODO send all funds from contract to address + std::stringstream ss; + ss << address; + const en_address_type en_address = ss.str(); + const auto& destination_wallet = _db.get_account_by_en_address(en_address); + + const auto& caller_contract_wallet = _db.get_account(owner); + + const auto value = caller_contract_wallet.balance.amount.value; + + if (value != 0) { + // TODO XXX value is set to be compatible with eth value, needs to be adjusted + auto callvalue = asset( value, XGT_SYMBOL ); + // TODO this should be the calling contract's wallet + _db.adjust_balance( caller_contract_wallet, -callvalue ); + _db.adjust_balance( destination_wallet, callvalue ); + } + + contract_object contract = _db.get_contract_by_wallet(owner); + _db.remove(contract); + + return true; + }; + + std::function< void(const machine::log_object&) > emit_log = [&](const machine::log_object& log) + { + _db.create< contract_log_object >( [&](contract_log_object& cl) + { + cl.contract_hash = contract_hash; + cl.owner = owner; + cl.topics.reserve(log.topics.size()); + for (auto topic : log.topics) + cl.topics.push_back(_db.bigint_to_hash(topic)); + cl.data = log.data; + }); + + return contract_hash.str(); + }; + + machine::chain_adapter adapter = { + sha3, + get_balance, + get_code_hash, + get_block_hash, + get_code_at_addr, + contract_create, + contract_call, + contract_callcode, + contract_delegatecall, + contract_staticcall, + contract_create2, + revert, + get_storage, + set_storage, + contract_return, + self_destruct, + emit_log + }; + + return adapter; } void contract_invoke_evaluator::do_apply( const contract_invoke_operation& op ) { - wlog("contract_invoke ${w}", ("w",op.contract_hash)); - /*const contract_hash_type contract_hash = op.contract_hash; + const contract_hash_type contract_hash = op.contract_hash; const auto& c = _db.get_contract(contract_hash); + uint64_t energy = 0; // TODO - const machine_context& ctx = { - true, // bool is_running - 0x5c477758 // uint64_t block_timestamp - }; - const vector& code = {0}; - machine m(ctx, code); - m.step(); */ - // // const auto& args = op.args; - // // const auto& caller = op.caller; - // // TODO: Invoke VM - - // // Generate receipt - // _db.create< contract_receipt_object >( [&](contract_receipt_object& cr) - // { - // // cr.id = std::static_cast(generate_random_ripmd160()); - // cr.contract_id = op.contract; - // cr.caller = op.caller; - // cr.args = op.args; - // }); + const contract_storage_object* cs = _db.find_contract_storage(contract_hash, c.owner); + + map< fc::sha256, fc::sha256 > storage; + if (cs != nullptr) { + storage = cs->data; + } + else { + storage = map< fc::sha256, fc::sha256 >(); + } + + std::vector unsigned_args; + std::copy(op.args.begin(), op.args.end(), std::back_inserter(unsigned_args)); + auto result = contract_invoke(_db, c.owner, op.caller, contract_hash, op.value, energy, unsigned_args, storage); + + if (cs != nullptr) { + _db.modify< contract_storage_object >(*cs, [&](contract_storage_object& cs) { + cs.contract = contract_hash; + cs.caller = c.owner; + cs.data = storage; + }); + } + else { + _db.create< contract_storage_object >([&](contract_storage_object& cs) { + cs.contract = contract_hash; + cs.caller = c.owner; + cs.data = storage; + }); + } } } } // xgt::chain diff --git a/libraries/fc/include/fc/crypto/ripemd160.hpp b/libraries/fc/include/fc/crypto/ripemd160.hpp index 912c3929..73dc82c8 100644 --- a/libraries/fc/include/fc/crypto/ripemd160.hpp +++ b/libraries/fc/include/fc/crypto/ripemd160.hpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace fc{ class sha512; @@ -24,6 +25,8 @@ class ripemd160 static ripemd160 hash( const fc::sha256& h ); static ripemd160 hash( const char* d, uint32_t dlen ); static ripemd160 hash( const string& ); + static string hex_digest( const string wallet_name ); + static boost::multiprecision::uint256_t uint256_t_digest( const string wallet_name ); template static ripemd160 hash( const T& t ) diff --git a/libraries/fc/include/fc/io/raw.hpp b/libraries/fc/include/fc/io/raw.hpp index 13574eb7..f43e5192 100644 --- a/libraries/fc/include/fc/io/raw.hpp +++ b/libraries/fc/include/fc/io/raw.hpp @@ -1,4 +1,6 @@ #pragma once +#include +#include #include #include #include @@ -13,6 +15,7 @@ #include #include #include +#include #include #include diff --git a/libraries/fc/src/crypto/ripemd160.cpp b/libraries/fc/src/crypto/ripemd160.cpp index 1ccfa5f9..2925f4d2 100644 --- a/libraries/fc/src/crypto/ripemd160.cpp +++ b/libraries/fc/src/crypto/ripemd160.cpp @@ -56,6 +56,35 @@ ripemd160 ripemd160::hash( const string& s ) { return hash( s.c_str(), s.size() ); } +string ripemd160::hex_digest(const string wallet_name) +{ + std::string prefix( "XGT" ); + + const size_t prefix_len = prefix.size(); + auto b58 = wallet_name.substr( prefix_len ); + auto r160 = fc::ripemd160::hash(b58); + + std::stringstream ss; + ss << std::hex << r160.str(); + + return ss.str(); +} + +boost::multiprecision::uint256_t uint256_t_digest( const string wallet_name ) +{ + std::string prefix( "XGT" ); + + const size_t prefix_len = prefix.size(); + auto b58 = wallet_name.substr( prefix_len ); + auto r160 = fc::ripemd160::hash(b58); + + std::stringstream ss; + ss << std::hex << r160.str(); + boost::multiprecision::uint256_t x; + ss >> x; + return x; +} + void ripemd160::encoder::write( const char* d, uint32_t dlen ) { RIPEMD160_Update( &my->ctx, d, dlen); } diff --git a/libraries/fc/vendor/rlpvalue/.gitignore b/libraries/fc/vendor/rlpvalue/.gitignore new file mode 100644 index 00000000..0203b4bb --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/.gitignore @@ -0,0 +1,32 @@ +.deps/ +INSTALL +Makefile +Makefile.in +aclocal.m4 +autom4te.cache/ +compile +config.log +config.status +config.guess +config.sub +configure +depcomp +install-sh +missing +stamp-h1 +rlpvalue-config.h* +test-driver +libtool +ltmain.sh +test-suite.log + +*.a +*.la +*.lo +*.logs +*.o +*.pc +*.trs + +.dirstamp +.libs diff --git a/libraries/fc/vendor/rlpvalue/.gitmodules b/libraries/fc/vendor/rlpvalue/.gitmodules new file mode 100644 index 00000000..a740b3a7 --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/.gitmodules @@ -0,0 +1,3 @@ +[submodule "univalue"] + path = univalue + url = https://github.com/jgarzik/univalue diff --git a/libraries/fc/vendor/rlpvalue/.travis.yml b/libraries/fc/vendor/rlpvalue/.travis.yml new file mode 100644 index 00000000..b5170879 --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/.travis.yml @@ -0,0 +1,58 @@ +language: cpp + +compiler: + - clang + - gcc + +os: + - linux + - osx + +sudo: true + +env: + global: + - MAKEJOBS=-j3 + - RUN_TESTS=true + - BASE_OUTDIR=$TRAVIS_BUILD_DIR/out + +cache: + apt: true + +addons: + apt: + packages: + - pkg-config + +before_install: + - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; fi + +install: + - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew install gettext; fi + - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew install argp-standalone; fi + +before_script: + - if [ -n "$USE_SHELL" ]; then export CONFIG_SHELL="$USE_SHELL"; fi + - test -n "$USE_SHELL" && eval '"$USE_SHELL" -c "./autogen.sh"' || ./autogen.sh + +script: + - if [ -n "$RLPVALUE_CONFIG" ]; then unset CC; unset CXX; fi + - OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST + - RLPVALUE_CONFIG_ALL="--prefix=$TRAVIS_BUILD_DIR/depends/$HOST --bindir=$OUTDIR/bin --libdir=$OUTDIR/lib" + - ./configure --cache-file=config.cache $RLPVALUE_CONFIG_ALL $RLPVALUE_CONFIG || ( cat config.log && false) + - make -s $MAKEJOBS $GOAL || ( echo "Build failure. Verbose build follows." && make $GOAL ; false ) + - export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/depends/$HOST/lib + - if [ "$RUN_TESTS" = "true" ]; then make $MAKEJOBS distcheck; fi + +#matrix: +# fast_finish: true +# include: +# - os: linux +# compiler: gcc +# env: RLPVALUE_CONFIG=--host=x86_64-w64-mingw32 RUN_TESTS=false +# addons: +# apt: +# packages: +# - g++-mingw-w64-x86-64 +# - gcc-mingw-w64-x86-64 +# - binutils-mingw-w64-x86-64 diff --git a/libraries/fc/vendor/rlpvalue/COPYING b/libraries/fc/vendor/rlpvalue/COPYING new file mode 100644 index 00000000..1fb429f3 --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/COPYING @@ -0,0 +1,19 @@ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/libraries/fc/vendor/rlpvalue/Makefile.am b/libraries/fc/vendor/rlpvalue/Makefile.am new file mode 100644 index 00000000..f83246df --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/Makefile.am @@ -0,0 +1,61 @@ +ACLOCAL_AMFLAGS = -I build-aux/m4 + +SUBDIRS = univalue + +UNIVALUE_CFLAGS = -I$(top_srcdir)/univalue/include + +include_HEADERS = include/rlpvalue.h +noinst_HEADERS = lib/rlpvalue_utffilter.h + +lib_LTLIBRARIES = librlpvalue.la + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = pc/librlpvalue.pc + +librlpvalue_la_SOURCES = \ + lib/rlpvalue.cpp \ + lib/rlpvalue_get.cpp \ + lib/rlpvalue_read.cpp \ + lib/rlpvalue_write.cpp + +librlpvalue_la_LDFLAGS = \ + -version-info $(LIBRLPVALUE_CURRENT):$(LIBRLPVALUE_REVISION):$(LIBRLPVALUE_AGE) \ + -no-undefined +librlpvalue_la_CXXFLAGS = -I$(top_srcdir)/include + +TESTS = test/object test/unitester + +noinst_PROGRAMS = src/rlp $(TESTS) + +src_rlp_SOURCES = \ + src/InfInt.h \ + src/tool.cpp \ + src/rlp2json.cpp \ + test/utilstrencodings.cpp +src_rlp_LDADD = librlpvalue.la univalue/.libs/libunivalue.a $(ARGP_LIBS) +src_rlp_CXXFLAGS = -I$(top_srcdir)/include $(UNIVALUE_CFLAGS) +src_rlp_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) + +TEST_DATA_DIR=test/data + +test_unitester_SOURCES = \ + src/rlp2json.cpp \ + test/unitester.cpp \ + test/utilstrencodings.h test/utilstrencodings.cpp +test_unitester_LDADD = librlpvalue.la univalue/.libs/libunivalue.a +test_unitester_CXXFLAGS = -I$(top_srcdir)/include $(UNIVALUE_CFLAGS) \ + -DJSON_TEST_SRC=\"$(srcdir)/$(TEST_DATA_DIR)\" +test_unitester_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) + +test_object_SOURCES = test/object.cpp +test_object_LDADD = librlpvalue.la +test_object_CXXFLAGS = -I$(top_srcdir)/include +test_object_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS) + +TEST_FILES = \ + test/data/example.json \ + test/data/invalidRLPTest.json \ + test/data/longlist.json \ + test/data/rlptest.json + +EXTRA_DIST=$(TEST_FILES) diff --git a/libraries/fc/vendor/rlpvalue/README.md b/libraries/fc/vendor/rlpvalue/README.md new file mode 100644 index 00000000..8df996c1 --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/README.md @@ -0,0 +1,22 @@ + +# RLPValue + +## Summary + +A universal value class for use with Ethereum RLP encoding/decoding. + +See https://github.com/ethereum/wiki/wiki/RLP for more. + +## Installation + +This project is a standard GNU +[autotools](https://www.gnu.org/software/automake/manual/html_node/Autotools-Introduction.html) +project. Build and install instructions are available in the `INSTALL` +file provided with GNU autotools. + +``` +$ ./autogen.sh +$ ./configure +$ make +``` + diff --git a/libraries/fc/vendor/rlpvalue/TODO.md b/libraries/fc/vendor/rlpvalue/TODO.md new file mode 100644 index 00000000..8e9b7dc0 --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/TODO.md @@ -0,0 +1,21 @@ + +# TO-DO + +## Technical debt + +* univalue included as a git subtree because of difficulty in + installing dependencies across all travis test platforms. + Ideally: remove submodule, discover via configure. + +* win64 build disabled in travis due to lack of argp-standalone + on that platform. find argp-standalone, and re-enable win64. + +## Low priority + +Rearrange tree for easier 'git subtree' style use + +Namespace support - must come up with useful shorthand, avoiding +long Univalue::Univalue::Univalue usages forced upon library users. + +Improve test suite + diff --git a/libraries/fc/vendor/rlpvalue/a.out b/libraries/fc/vendor/rlpvalue/a.out new file mode 100755 index 00000000..1a3af65d Binary files /dev/null and b/libraries/fc/vendor/rlpvalue/a.out differ diff --git a/libraries/fc/vendor/rlpvalue/autogen.sh b/libraries/fc/vendor/rlpvalue/autogen.sh new file mode 100755 index 00000000..e02f905f --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/autogen.sh @@ -0,0 +1,18 @@ +#!/bin/sh +# Copyright (c) 2013-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +set -e +srcdir="$(dirname $0)" +cd "$srcdir" +if [ -z ${LIBTOOLIZE} ] && GLIBTOOLIZE="`which glibtoolize 2>/dev/null`"; then + LIBTOOLIZE="${GLIBTOOLIZE}" + export LIBTOOLIZE +fi +which autoreconf >/dev/null || \ + (echo "configuration failed, please install autoconf first" && exit 1) +autoreconf --install --force --warnings=all + +cd univalue && ./autogen.sh + diff --git a/libraries/fc/vendor/rlpvalue/configure.ac b/libraries/fc/vendor/rlpvalue/configure.ac new file mode 100644 index 00000000..24737780 --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/configure.ac @@ -0,0 +1,78 @@ +m4_define([librlpvalue_major_version], [1]) +m4_define([librlpvalue_minor_version], [1]) +m4_define([librlpvalue_micro_version], [4]) +m4_define([librlpvalue_interface_age], [4]) +# If you need a modifier for the version number. +# Normally empty, but can be used to make "fixup" releases. +m4_define([librlpvalue_extraversion], []) + +dnl libtool versioning from librlpvalue +m4_define([librlpvalue_current], [m4_eval(100 * librlpvalue_minor_version + librlpvalue_micro_version - librlpvalue_interface_age)]) +m4_define([librlpvalue_binary_age], [m4_eval(100 * librlpvalue_minor_version + librlpvalue_micro_version)]) +m4_define([librlpvalue_revision], [librlpvalue_interface_age]) +m4_define([librlpvalue_age], [m4_eval(librlpvalue_binary_age - librlpvalue_interface_age)]) +m4_define([librlpvalue_version], [librlpvalue_major_version().librlpvalue_minor_version().librlpvalue_micro_version()librlpvalue_extraversion()]) + + +AC_INIT([rlpvalue], [0.0.1], + [http://github.com/jgarzik/rlpvalue/]) + +dnl make the compilation flags quiet unless V=1 is used +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +AC_PREREQ(2.60) +AC_CONFIG_SRCDIR([lib/rlpvalue.cpp]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_MACRO_DIR([build-aux/m4]) +AC_CONFIG_HEADERS([rlpvalue-config.h]) +AX_SUBDIRS_CONFIGURE([univalue], [--disable-shared]) +AM_INIT_AUTOMAKE([subdir-objects foreign]) + +dnl Require C++11 compiler (no GNU extensions) +AC_PROG_CXX +AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory], [nodefault]) +AC_LANG(C++) + +LIBRLPVALUE_MAJOR_VERSION=librlpvalue_major_version +LIBRLPVALUE_MINOR_VERSION=librlpvalue_minor_version +LIBRLPVALUE_MICRO_VERSION=librlpvalue_micro_version +LIBRLPVALUE_INTERFACE_AGE=librlpvalue_interface_age + +# ABI version +# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html +LIBRLPVALUE_CURRENT=librlpvalue_current +LIBRLPVALUE_REVISION=librlpvalue_revision +LIBRLPVALUE_AGE=librlpvalue_age + +AC_CHECK_LIB(argp, argp_parse, ARGP_LIBS=-largp) +AC_SUBST(ARGP_LIBS) + +AC_SUBST(LIBRLPVALUE_CURRENT) +AC_SUBST(LIBRLPVALUE_REVISION) +AC_SUBST(LIBRLPVALUE_AGE) + +LT_INIT +LT_LANG([C++]) + +case $host in + *mingw*) + LIBTOOL_APP_LDFLAGS="$LIBTOOL_APP_LDFLAGS -all-static" + ;; +esac + +BUILD_EXEEXT= +case $build in + *mingw*) + BUILD_EXEEXT=".exe" + ;; +esac + +AC_CONFIG_FILES([ + Makefile + pc/librlpvalue.pc + pc/librlpvalue-uninstalled.pc]) + +AC_SUBST(LIBTOOL_APP_LDFLAGS) +AC_SUBST(BUILD_EXEEXT) +AC_OUTPUT + diff --git a/libraries/fc/vendor/rlpvalue/gen/gen.cpp b/libraries/fc/vendor/rlpvalue/gen/gen.cpp new file mode 100644 index 00000000..be3d4ccf --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/gen/gen.cpp @@ -0,0 +1,82 @@ +// Copyright 2014 BitPay Inc. +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. + +// +// To re-create univalue_escapes.h: +// $ g++ -o gen gen.cpp +// $ ./gen > univalue_escapes.h +// + +#include +#include +#include "univalue.h" + +static bool initEscapes; +static std::string escapes[256]; + +static void initJsonEscape() +{ + // Escape all lower control characters (some get overridden with smaller sequences below) + for (int ch=0x00; ch<0x20; ++ch) { + char tmpbuf[20]; + snprintf(tmpbuf, sizeof(tmpbuf), "\\u%04x", ch); + escapes[ch] = std::string(tmpbuf); + } + + escapes[(int)'"'] = "\\\""; + escapes[(int)'\\'] = "\\\\"; + escapes[(int)'\b'] = "\\b"; + escapes[(int)'\f'] = "\\f"; + escapes[(int)'\n'] = "\\n"; + escapes[(int)'\r'] = "\\r"; + escapes[(int)'\t'] = "\\t"; + escapes[(int)'\x7f'] = "\\u007f"; // U+007F DELETE + + initEscapes = true; +} + +static void outputEscape() +{ + printf( "// Automatically generated file. Do not modify.\n" + "#ifndef BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n" + "#define BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n" + "static const char *escapes[256] = {\n"); + + for (unsigned int i = 0; i < 256; i++) { + if (escapes[i].empty()) { + printf("\tNULL,\n"); + } else { + printf("\t\""); + + unsigned int si; + for (si = 0; si < escapes[i].size(); si++) { + char ch = escapes[i][si]; + switch (ch) { + case '"': + printf("\\\""); + break; + case '\\': + printf("\\\\"); + break; + default: + printf("%c", escapes[i][si]); + break; + } + } + + printf("\",\n"); + } + } + + printf( "};\n" + "#endif // BITCOIN_UNIVALUE_UNIVALUE_ESCAPES_H\n"); +} + +int main (int argc, char *argv[]) +{ + initJsonEscape(); + outputEscape(); + return 0; +} + diff --git a/libraries/fc/vendor/rlpvalue/include/rlpvalue.h b/libraries/fc/vendor/rlpvalue/include/rlpvalue.h new file mode 100644 index 00000000..afebcd7d --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/include/rlpvalue.h @@ -0,0 +1,126 @@ +// Copyright 2014 BitPay Inc. +// Copyright 2015 Bitcoin Core Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. + +#ifndef __RLPVALUE_H__ +#define __RLPVALUE_H__ + +#include +#include + +#include +#include +#include +#include + +#include // std::pair + +enum RLP_constants { + RLP_maxUintLen = 8, + RLP_bufferLenStart = 0x80, + RLP_listStart = 0xc0, +}; + +// really, a generic buffer, but we are in the global namespace, hence a prefix +class RLPBuffer { +public: + std::vector data; + + RLPBuffer() {} + RLPBuffer(const RLPBuffer& other) : data(other.data) {} + + void clear() { data.clear(); } + void reserve(size_t n) { data.reserve(n); } + void push_back(unsigned char ch) { data.push_back(ch); } + + std::vector::iterator begin() { return data.begin(); } + std::vector::iterator end() { return data.end(); } + + const unsigned char *get() const { return &data[0]; } + size_t size() const { return data.size(); } + std::string toStr() const { + std::string rs((const char *) &data[0], data.size()); + return rs; + } +}; + +// a single RLP value... which could be a nested list of RLP values +class RLPValue { +public: + enum VType { VARR, VBUF, }; + + RLPValue() { typ = VBUF; } + RLPValue(RLPValue::VType initialType) { + typ = initialType; + } + RLPValue(const std::string& val_) { + assign(val_); + } + RLPValue(const char *val_) { + std::string s(val_); + assign(s); + } + ~RLPValue() {} + + void clear(); + + void assign(const std::vector& val); + void assign(const std::string& val); + + bool setArray(); + + enum VType getType() const { return typ; } + std::string getValStr() const { return val.toStr(); } + bool empty() const { return (values.size() == 0); } + + size_t size() const { return values.size(); } + + const RLPValue& operator[](size_t index) const; + + bool isBuffer() const { return (typ == VBUF); } + bool isArray() const { return (typ == VARR); } + + bool push_back(const RLPValue& val); + bool push_back(const std::string& val_) { + RLPValue tmpVal; + tmpVal.assign(val_); + return push_back(tmpVal); + } + bool push_back(const char *val_) { + std::string s(val_); + return push_back(s); + } + bool push_backV(const std::vector& vec); + + std::string write() const; + + bool read(const unsigned char *raw, size_t len, + size_t& consumed, size_t& wanted); + +private: + bool readArray(const unsigned char *raw, size_t len, + size_t uintlen, size_t payloadlen, + size_t& consumed, size_t& wanted); + RLPValue::VType typ; + RLPBuffer val; + std::vector values; + + void writeBuffer(std::string& s) const; + void writeArray(std::string& s) const; + +public: + // Strict type-specific getters, these throw std::runtime_error if the + // value is of unexpected type + const std::vector& getValues() const; + std::string get_str() const; + const RLPValue& get_array() const; + + enum VType type() const { return getType(); } +}; + +extern const char *uvTypeName(RLPValue::VType t); + +extern const RLPValue NullRLPValue; + +#endif // __RLPVALUE_H__ diff --git a/libraries/fc/vendor/rlpvalue/lib/.gitignore b/libraries/fc/vendor/rlpvalue/lib/.gitignore new file mode 100644 index 00000000..ee7fc285 --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/lib/.gitignore @@ -0,0 +1,2 @@ +gen +.libs diff --git a/libraries/fc/vendor/rlpvalue/lib/rlpvalue.cpp b/libraries/fc/vendor/rlpvalue/lib/rlpvalue.cpp new file mode 100644 index 00000000..6872f0e2 --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/lib/rlpvalue.cpp @@ -0,0 +1,84 @@ +// Copyright 2014 BitPay Inc. +// Copyright 2015 Bitcoin Core Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include + +#include "../include/rlpvalue.h" + +const RLPValue NullRLPValue; + +void RLPValue::clear() +{ + typ = VBUF; + val.clear(); + values.clear(); +} + +void RLPValue::assign(const std::string& s) +{ + clear(); + + val.reserve(s.size()); + + for (auto it = s.begin(); it != s.end(); it++) { + val.push_back((unsigned char) *it); + } +} + +void RLPValue::assign(const std::vector& buf) +{ + val.data.assign(buf.begin(), buf.end()); +} + +bool RLPValue::setArray() +{ + clear(); + typ = VARR; + return true; +} + +bool RLPValue::push_back(const RLPValue& val_) +{ + if (typ != VARR) + return false; + + values.push_back(val_); + return true; +} + +bool RLPValue::push_backV(const std::vector& vec) +{ + if (typ != VARR) + return false; + + values.insert(values.end(), vec.begin(), vec.end()); + + return true; +} + +const RLPValue& RLPValue::operator[](size_t index) const +{ + if (typ != VARR) + return NullRLPValue; + if (index >= values.size()) + return NullRLPValue; + + return values.at(index); +} + +const char *uvTypeName(RLPValue::VType t) +{ + switch (t) { + case RLPValue::VARR: return "array"; + case RLPValue::VBUF: return "buffer"; + } + + // not reached + return NULL; +} + diff --git a/libraries/fc/vendor/rlpvalue/lib/rlpvalue_get.cpp b/libraries/fc/vendor/rlpvalue/lib/rlpvalue_get.cpp new file mode 100644 index 00000000..82fb663b --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/lib/rlpvalue_get.cpp @@ -0,0 +1,38 @@ +// Copyright 2014 BitPay Inc. +// Copyright 2015 Bitcoin Core Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../include/rlpvalue.h" + +const std::vector& RLPValue::getValues() const +{ + if (typ != VARR) + throw std::runtime_error("JSON value is not an object or array as expected"); + return values; +} + +std::string RLPValue::get_str() const +{ + if (typ != VBUF) + throw std::runtime_error("JSON value is not a string as expected"); + return getValStr(); +} + +const RLPValue& RLPValue::get_array() const +{ + if (typ != VARR) + throw std::runtime_error("JSON value is not an array as expected"); + return *this; +} + diff --git a/libraries/fc/vendor/rlpvalue/lib/rlpvalue_read.cpp b/libraries/fc/vendor/rlpvalue/lib/rlpvalue_read.cpp new file mode 100644 index 00000000..5b317a28 --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/lib/rlpvalue_read.cpp @@ -0,0 +1,216 @@ +// Copyright 2014 BitPay Inc. +// Copyright 2019 Bloq Inc. +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. + +#include +#include +#include "../include/rlpvalue.h" + +uint64_t toInteger(const unsigned char *raw, size_t len) +{ + if (len == 0) + return 0; + else if (len == 1) + return *raw; + else + return (raw[len - 1]) + (toInteger(raw, len - 1) * 256); +} + +bool RLPValue::readArray(const unsigned char *raw, size_t len, + size_t uintlen, size_t payloadlen, + size_t& consumed, size_t& wanted) +{ + const size_t prefixlen = 1; + + // validate list length, including possible addition overflows. + size_t expected = prefixlen + uintlen + payloadlen; + if ((expected > len) || (payloadlen > len)) { + wanted = expected > payloadlen ? expected : payloadlen; + return false; + } + + // we are type=array + if (!setArray()) + return false; + + size_t child_len = payloadlen; + size_t child_wanted = 0; + size_t total_consumed = 0; + + const unsigned char *list_ent = raw + prefixlen + uintlen; + + // recursively read until payloadlen bytes parsed, or error + while (child_len > 0) { + RLPValue childVal; + size_t child_consumed = 0; + + if (!childVal.read(list_ent, child_len, + child_consumed, child_wanted)) + return false; + + total_consumed += child_consumed; + list_ent += child_consumed; + child_len -= child_consumed; + + values.push_back(childVal); + } + + consumed = total_consumed; + return true; +} + +bool RLPValue::read(const unsigned char *raw, size_t len, + size_t& consumed, size_t& wanted) +{ + clear(); + consumed = 0; + wanted = 0; + + std::vector stack; + std::vector buf; + const unsigned char* end = raw + len; + + const size_t prefixlen = 1; + + unsigned char ch = *raw; + + if (len < 1) { + wanted = 1; + goto out_fail; + } + + // Case 1: [prefix is 1-byte data buffer] + if (ch <= 0x7f) { + const unsigned char *tok_start = raw; + const unsigned char *tok_end = tok_start + prefixlen; + assert(tok_end <= end); + + // parsing done; assign data buffer value. + buf.assign(tok_start, tok_end); + assign(buf); + + consumed = buf.size(); + + // Case 2: [prefix, including buffer length][data] + } else if ((ch >= 0x80) && (ch <= 0xb7)) { + size_t blen = ch - 0x80; + size_t expected = prefixlen + blen; + + if (len < expected) { + wanted = expected; + goto out_fail; + } + + const unsigned char *tok_start = raw + 1; + const unsigned char *tok_end = tok_start + blen; + assert(tok_end <= end); + + // require minimal encoding + if ((blen == 1) && (tok_start[0] <= 0x7f)) + goto out_fail; + + // parsing done; assign data buffer value. + buf.assign(tok_start, tok_end); + assign(buf); + + consumed = expected; + + // Case 3: [prefix][buffer length][data] + } else if ((ch >= 0xb8) && (ch <= 0xbf)) { + size_t uintlen = ch - 0xb7; + size_t expected = prefixlen + uintlen; + + if (len < expected) { + wanted = expected; + goto out_fail; + } + + assert(uintlen > 0 && uintlen <= RLP_maxUintLen); + + const unsigned char *tok_start = raw + prefixlen; + if ((uintlen > 1) && (tok_start[0] == 0)) // no leading zeroes + goto out_fail; + + // read buffer length + uint64_t slen = toInteger(tok_start, uintlen); + + // validate buffer length, including possible addition overflows. + expected = prefixlen + uintlen + slen; + if ((slen < (RLP_listStart - RLP_bufferLenStart - RLP_maxUintLen)) || + (expected > len) || (slen > len)) { + wanted = slen > expected ? slen : expected; + goto out_fail; + } + + // parsing done; assign data buffer value. + tok_start = raw + prefixlen + uintlen; + const unsigned char *tok_end = tok_start + slen; + buf.assign(tok_start, tok_end); + assign(buf); + + consumed = expected; + + // Case 4: [prefix][list] + } else if ((ch >= 0xc0) && (ch <= 0xf7)) { + size_t payloadlen = ch - 0xc0; + size_t expected = prefixlen + payloadlen; + size_t list_consumed = 0; + size_t list_wanted = 0; + + // read list payload + if (!readArray(raw, len, 0, payloadlen, list_consumed, list_wanted)) { + wanted = list_wanted; + goto out_fail; + } + + assert(list_consumed == payloadlen); + + consumed = expected; + + // Case 5: [prefix][list length][list] + } else { + assert((ch >= 0xf8) && (ch <= 0xff)); + + size_t uintlen = ch - 0xf7; + size_t expected = prefixlen + uintlen; + + if (len < expected) { + wanted = expected; + goto out_fail; + } + + assert(uintlen > 0 && uintlen <= RLP_maxUintLen); + + const unsigned char *tok_start = raw + prefixlen; + if ((uintlen > 1) && (tok_start[0] == 0)) // no leading zeroes + goto out_fail; + + // read list length + size_t payloadlen = toInteger(tok_start, uintlen); + + // special requirement for non-immediate length + if (payloadlen < (0x100 - RLP_listStart - RLP_maxUintLen)) + goto out_fail; + + size_t list_consumed = 0; + size_t list_wanted = 0; + + // read list payload + if (!readArray(raw, len, uintlen, payloadlen, list_consumed, list_wanted)) { + wanted = list_wanted; + goto out_fail; + } + + assert(list_consumed == payloadlen); + + consumed = prefixlen + uintlen + payloadlen; + } + + return true; + +out_fail: + clear(); + return false; +} + diff --git a/libraries/fc/vendor/rlpvalue/lib/rlpvalue_utffilter.h b/libraries/fc/vendor/rlpvalue/lib/rlpvalue_utffilter.h new file mode 100644 index 00000000..da1bde02 --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/lib/rlpvalue_utffilter.h @@ -0,0 +1,119 @@ +// Copyright 2016 Wladimir J. van der Laan +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. +#ifndef RLPVALUE_UTFFILTER_H +#define RLPVALUE_UTFFILTER_H + +#include + +/** + * Filter that generates and validates UTF-8, as well as collates UTF-16 + * surrogate pairs as specified in RFC4627. + */ +class JSONUTF8StringFilter +{ +public: + explicit JSONUTF8StringFilter(std::string &s): + str(s), is_valid(true), codepoint(0), state(0), surpair(0) + { + } + // Write single 8-bit char (may be part of UTF-8 sequence) + void push_back(unsigned char ch) + { + if (state == 0) { + if (ch < 0x80) // 7-bit ASCII, fast direct pass-through + str.push_back(ch); + else if (ch < 0xc0) // Mid-sequence character, invalid in this state + is_valid = false; + else if (ch < 0xe0) { // Start of 2-byte sequence + codepoint = (ch & 0x1f) << 6; + state = 6; + } else if (ch < 0xf0) { // Start of 3-byte sequence + codepoint = (ch & 0x0f) << 12; + state = 12; + } else if (ch < 0xf8) { // Start of 4-byte sequence + codepoint = (ch & 0x07) << 18; + state = 18; + } else // Reserved, invalid + is_valid = false; + } else { + if ((ch & 0xc0) != 0x80) // Not a continuation, invalid + is_valid = false; + state -= 6; + codepoint |= (ch & 0x3f) << state; + if (state == 0) + push_back_u(codepoint); + } + } + // Write codepoint directly, possibly collating surrogate pairs + void push_back_u(unsigned int codepoint_) + { + if (state) // Only accept full codepoints in open state + is_valid = false; + if (codepoint_ >= 0xD800 && codepoint_ < 0xDC00) { // First half of surrogate pair + if (surpair) // Two subsequent surrogate pair openers - fail + is_valid = false; + else + surpair = codepoint_; + } else if (codepoint_ >= 0xDC00 && codepoint_ < 0xE000) { // Second half of surrogate pair + if (surpair) { // Open surrogate pair, expect second half + // Compute code point from UTF-16 surrogate pair + append_codepoint(0x10000 | ((surpair - 0xD800)<<10) | (codepoint_ - 0xDC00)); + surpair = 0; + } else // Second half doesn't follow a first half - fail + is_valid = false; + } else { + if (surpair) // First half of surrogate pair not followed by second - fail + is_valid = false; + else + append_codepoint(codepoint_); + } + } + // Check that we're in a state where the string can be ended + // No open sequences, no open surrogate pairs, etc + bool finalize() + { + if (state || surpair) + is_valid = false; + return is_valid; + } +private: + std::string &str; + bool is_valid; + // Current UTF-8 decoding state + unsigned int codepoint; + int state; // Top bit to be filled in for next UTF-8 byte, or 0 + + // Keep track of the following state to handle the following section of + // RFC4627: + // + // To escape an extended character that is not in the Basic Multilingual + // Plane, the character is represented as a twelve-character sequence, + // encoding the UTF-16 surrogate pair. So, for example, a string + // containing only the G clef character (U+1D11E) may be represented as + // "\uD834\uDD1E". + // + // Two subsequent \u.... may have to be replaced with one actual codepoint. + unsigned int surpair; // First half of open UTF-16 surrogate pair, or 0 + + void append_codepoint(unsigned int codepoint_) + { + if (codepoint_ <= 0x7f) + str.push_back((char)codepoint_); + else if (codepoint_ <= 0x7FF) { + str.push_back((char)(0xC0 | (codepoint_ >> 6))); + str.push_back((char)(0x80 | (codepoint_ & 0x3F))); + } else if (codepoint_ <= 0xFFFF) { + str.push_back((char)(0xE0 | (codepoint_ >> 12))); + str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F))); + str.push_back((char)(0x80 | (codepoint_ & 0x3F))); + } else if (codepoint_ <= 0x1FFFFF) { + str.push_back((char)(0xF0 | (codepoint_ >> 18))); + str.push_back((char)(0x80 | ((codepoint_ >> 12) & 0x3F))); + str.push_back((char)(0x80 | ((codepoint_ >> 6) & 0x3F))); + str.push_back((char)(0x80 | (codepoint_ & 0x3F))); + } + } +}; + +#endif diff --git a/libraries/fc/vendor/rlpvalue/lib/rlpvalue_write.cpp b/libraries/fc/vendor/rlpvalue/lib/rlpvalue_write.cpp new file mode 100644 index 00000000..53449ecd --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/lib/rlpvalue_write.cpp @@ -0,0 +1,83 @@ +// Copyright 2014 BitPay Inc. +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. + +#include +#include +#include "../include/rlpvalue.h" + +std::string RLPValue::write() const +{ + std::string s; + + switch (typ) { + case VARR: + writeArray(s); + break; + case VBUF: + writeBuffer(s); + break; + } + + return s; +} + +std::string encodeBinary(uint64_t n) +{ + std::string rs; + + if (n == 0) { + // do nothing; return empty string + } else { + rs.assign(encodeBinary(n / 256)); + + unsigned char ch = n % 256; + rs.append((const char *) &ch, 1); + } + + return rs; +} + +static std::string encodeLength(size_t n, unsigned char offset) +{ + std::string rs; + + if (n < 56) { + unsigned char ch = n + offset; + rs.assign((const char *) &ch, 1); + } + + else { + // assert(n too big); + std::string binlen = encodeBinary(n); + + unsigned char ch = binlen.size() + offset + 55; + rs.assign((const char *) &ch, 1); + rs.append(binlen); + } + + return rs; +} + +void RLPValue::writeBuffer(std::string& s) const +{ + const unsigned char *p = val.size() ? val.get() : nullptr; + size_t sz = val.size(); + + if ((sz == 1) && (p[0] < 0x80)) + s.append((const char *) p, 1); + else + s += encodeLength(sz, 0x80) + val.toStr(); +} + +void RLPValue::writeArray(std::string& s) const +{ + std::string tmp; + for (auto it = values.begin(); it != values.end(); it++) { + const RLPValue& val = *it; + tmp += val.write(); + } + + s += encodeLength(tmp.size(), 0xC0) + tmp; +} + diff --git a/libraries/fc/vendor/rlpvalue/main.cpp b/libraries/fc/vendor/rlpvalue/main.cpp new file mode 100644 index 00000000..11427efb --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/main.cpp @@ -0,0 +1,48 @@ +#include "include/rlpvalue.h" +#include "lib/rlpvalue.cpp" +#include "lib/rlpvalue_get.cpp" +#include "lib/rlpvalue_write.cpp" +#include "test/utilstrencodings.cpp" +#include + +int main() { + std::string dogIns = "dog"; + std::string dogOuts = "83646f67"; + + // Parse input string + RLPValue dogV = RLPValue(dogIns); + + // Parse expected output, print corresponding input -- note that 0x has been stripped from hex output + std::vector outb = ParseHex(dogOuts); + std::string outbStr(outb.begin(), outb.end()); + + std::cout << "83646f67 to c_str:" << std::endl; + std::cout << outbStr << std::endl; + + // Generate output rlp-encoded hex + std::string dogGenOutput = dogV.write(); + std::string dogGenHex = HexStr( dogGenOutput.begin(), dogGenOutput.end() ); + + // Inspect type of RLP value -- buffer/array + std::cout << "\nRLPValue type: " << std::endl; + std::cout << uvTypeName( dogV.type() ) << "\n\n" << std::endl; + + + + std::string catIns = "cat"; + std::string catOuts = "83636174"; + + RLPValue catV = RLPValue(catIns); + + // Generate output rlp-encoded hex + std::string catGenOutput = catV.write(); + std::string catGenHex = HexStr( catGenOutput.begin(), catGenOutput.end() ); + + std::cout << "Cat to RLP:" << std::endl; + std::cout << catGenHex.c_str() << std::endl; + + std::cout << "\nRLPValue type: " << std::endl; + std::cout << uvTypeName( dogV.type() ) << std::endl; + + return 0; +} diff --git a/libraries/fc/vendor/rlpvalue/pc/librlpvalue-uninstalled.pc.in b/libraries/fc/vendor/rlpvalue/pc/librlpvalue-uninstalled.pc.in new file mode 100644 index 00000000..484bccfc --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/pc/librlpvalue-uninstalled.pc.in @@ -0,0 +1,9 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: librlpvalue +Description: librlpvalue, C++ universal value object and JSON library +Version: @VERSION@ +Libs: ${pc_top_builddir}/${pcfiledir}/librlpvalue.la diff --git a/libraries/fc/vendor/rlpvalue/pc/librlpvalue.pc.in b/libraries/fc/vendor/rlpvalue/pc/librlpvalue.pc.in new file mode 100644 index 00000000..faf5e647 --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/pc/librlpvalue.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: librlpvalue +Description: librlpvalue, C++ universal value object and JSON library +Version: @VERSION@ +Libs: -L${libdir} -lrlpvalue +Cflags: -I${includedir} diff --git a/libraries/fc/vendor/rlpvalue/src/.gitignore b/libraries/fc/vendor/rlpvalue/src/.gitignore new file mode 100644 index 00000000..771e1508 --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/src/.gitignore @@ -0,0 +1,3 @@ + +rlp + diff --git a/libraries/fc/vendor/rlpvalue/src/InfInt.h b/libraries/fc/vendor/rlpvalue/src/InfInt.h new file mode 100644 index 00000000..14ff2158 --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/src/InfInt.h @@ -0,0 +1,1371 @@ +/* + * InfInt - Arbitrary-Precision Integer Arithmetic Library + * Copyright (C) 2013 Sercan Tutar + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * + * USAGE: + * It is pretty straight forward to use the library. Just create an instance of + * InfInt class and start using it. + * + * Useful methods: + * intSqrt: integer square root operation + * digitAt: returns digit at index + * numberOfDigits: returns number of digits + * size: returns size in bytes + * toString: converts it to a string + * + * There are also conversion methods which allow conversion to primitive types: + * toInt, toLong, toLongLong, toUnsignedInt, toUnsignedLong, toUnsignedLongLong. + * + * You may define INFINT_USE_EXCEPTIONS and library methods will start raising + * InfIntException in case of error instead of writing error messages using + * std::cerr. + * + * See ReadMe.txt for more info. + * + * + * No overflows, happy programmers! + * + */ + +#ifndef INFINT_H_ +#define INFINT_H_ + +#include +#include +#include +#include +#include + +//#include +//#include + +#ifndef LONG_LONG_MIN +#define LONG_LONG_MIN std::numeric_limits::min() +#define LONG_LONG_MAX std::numeric_limits::max() +#define ULONG_LONG_MAX std::numeric_limits::max() +#endif + +#ifdef INFINT_USE_EXCEPTIONS +#include +#endif + +typedef int ELEM_TYPE; +typedef long long PRODUCT_TYPE; +static const ELEM_TYPE BASE = 1000000000; +static const ELEM_TYPE UPPER_BOUND = 999999999; +static const ELEM_TYPE DIGIT_COUNT = 9; +static const int powersOfTen[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 }; + +#ifdef INFINT_USE_EXCEPTIONS +class InfIntException: public std::exception +{ +public: + InfIntException(const std::string& txt) throw (); + ~InfIntException() throw (); + const char* what() const throw (); +private: + std::string txt; +}; + +inline InfIntException::InfIntException(const std::string& txt) throw () : +std::exception(), txt(txt) +{ +} + +inline InfIntException::~InfIntException() throw () +{ +} + +inline const char* InfIntException::what() const throw () +{ + return txt.c_str(); +} +#endif + +inline static div_t my_div(int num, int denom) +{ + div_t result; + result.quot = num / denom; + result.rem = num - denom * result.quot; + return result; +} + +inline static ldiv_t my_ldiv(long num, long denom) +{ + ldiv_t result; + result.quot = num / denom; + result.rem = num - denom * result.quot; + return result; +} + +inline static lldiv_t my_lldiv(long long num, long long denom) +{ + lldiv_t result; + result.quot = num / denom; + result.rem = num - denom * result.quot; + return result; +} + +class InfInt +{ + friend std::ostream& operator<<(std::ostream &s, const InfInt &n); + friend std::istream& operator>>(std::istream &s, InfInt &val); + +public: + /* constructors */ + InfInt(); + InfInt(const char* c); + InfInt(const std::string& s); + InfInt(int l); + InfInt(long l); + InfInt(long long l); + InfInt(unsigned int l); + InfInt(unsigned long l); + InfInt(unsigned long long l); + InfInt(const InfInt& l); + + /* assignment operators */ + const InfInt& operator=(const char* c); + const InfInt& operator=(const std::string& s); + const InfInt& operator=(int l); + const InfInt& operator=(long l); + const InfInt& operator=(long long l); + const InfInt& operator=(unsigned int l); + const InfInt& operator=(unsigned long l); + const InfInt& operator=(unsigned long long l); + const InfInt& operator=(const InfInt& l); + + /* unary increment/decrement operators */ + const InfInt& operator++(); + const InfInt& operator--(); + InfInt operator++(int); + InfInt operator--(int); + + /* operational assignments */ + const InfInt& operator+=(const InfInt& rhs); + const InfInt& operator-=(const InfInt& rhs); + const InfInt& operator*=(const InfInt& rhs); + const InfInt& operator/=(const InfInt& rhs); // throw + const InfInt& operator%=(const InfInt& rhs); // throw + const InfInt& operator*=(ELEM_TYPE rhs); + + /* operations */ + InfInt operator-() const; + InfInt operator+(const InfInt& rhs) const; + InfInt operator-(const InfInt& rhs) const; + InfInt operator*(const InfInt& rhs) const; + InfInt operator/(const InfInt& rhs) const; // throw + InfInt operator%(const InfInt& rhs) const; // throw + InfInt operator*(ELEM_TYPE rhs) const; + + /* relational operations */ + bool operator==(const InfInt& rhs) const; + bool operator!=(const InfInt& rhs) const; + bool operator<(const InfInt& rhs) const; + bool operator<=(const InfInt& rhs) const; + bool operator>(const InfInt& rhs) const; + bool operator>=(const InfInt& rhs) const; + + /* integer square root */ + InfInt intSqrt() const; // throw + + /* digit operations */ + char digitAt(size_t i) const; // throw + size_t numberOfDigits() const; + + /* size in bytes */ + size_t size() const; + + /* string conversion */ + std::string toString() const; + + /* conversion to primitive types */ + int toInt() const; // throw + long toLong() const; // throw + long long toLongLong() const; // throw + unsigned int toUnsignedInt() const; // throw + unsigned long toUnsignedLong() const; // throw + unsigned long long toUnsignedLongLong() const; // throw + +private: + static ELEM_TYPE dInR(const InfInt& R, const InfInt& D); + static void multiplyByDigit(ELEM_TYPE factor, std::vector& val); + + void correct(bool justCheckLeadingZeros = false, bool hasValidSign = false); + void fromString(const std::string& s); + void optimizeSqrtSearchBounds(InfInt& lo, InfInt& hi) const; + void truncateToBase(); + bool equalizeSigns(); + void removeLeadingZeros(); + + std::vector val; // number with base FACTOR + bool pos; // true if number is positive +}; + +inline InfInt::InfInt() : pos(true) +{ + //PROFINY_SCOPE + val.push_back((ELEM_TYPE) 0); +} + +inline InfInt::InfInt(const char* c) +{ + //PROFINY_SCOPE + fromString(c); +} + +inline InfInt::InfInt(const std::string& s) +{ + //PROFINY_SCOPE + fromString(s); +} + +inline InfInt::InfInt(int l) : pos(l >= 0) +{ + //PROFINY_SCOPE + bool subtractOne = false; + if (l == INT_MIN) + { + subtractOne = true; + ++l; + } + + if (!pos) + { + l = -l; + } + do + { + div_t dt = my_div(l, BASE); + val.push_back((ELEM_TYPE) dt.rem); + l = dt.quot; + } while (l > 0); + + if (subtractOne) + { + --*this; + } +} + +inline InfInt::InfInt(long l) : pos(l >= 0) +{ + //PROFINY_SCOPE + bool subtractOne = false; + if (l == LONG_MIN) + { + subtractOne = true; + ++l; + } + + if (!pos) + { + l = -l; + } + do + { + ldiv_t dt = my_ldiv(l, BASE); + val.push_back((ELEM_TYPE) dt.rem); + l = dt.quot; + } while (l > 0); + + if (subtractOne) + { + --*this; + } +} + +inline InfInt::InfInt(long long l) : pos(l >= 0) +{ + //PROFINY_SCOPE + bool subtractOne = false; + if (l == LONG_LONG_MIN) + { + subtractOne = true; + ++l; + } + + if (!pos) + { + l = -l; + } + do + { + lldiv_t dt = my_lldiv(l, BASE); + val.push_back((ELEM_TYPE) dt.rem); + l = dt.quot; + } while (l > 0); + + if (subtractOne) + { + --*this; + } +} + +inline InfInt::InfInt(unsigned int l) : pos(true) +{ + //PROFINY_SCOPE + do + { + val.push_back((ELEM_TYPE) (l % BASE)); + l = l / BASE; + } while (l > 0); +} + +inline InfInt::InfInt(unsigned long l) : pos(true) +{ + //PROFINY_SCOPE + do + { + val.push_back((ELEM_TYPE) (l % BASE)); + l = l / BASE; + } while (l > 0); +} + +inline InfInt::InfInt(unsigned long long l) : pos(true) +{ + //PROFINY_SCOPE + do + { + val.push_back((ELEM_TYPE) (l % BASE)); + l = l / BASE; + } while (l > 0); +} + +inline InfInt::InfInt(const InfInt& l) : val(l.val), pos(l.pos) +{ + //PROFINY_SCOPE +} + +inline const InfInt& InfInt::operator=(const char* c) +{ + //PROFINY_SCOPE + fromString(c); + return *this; +} + +inline const InfInt& InfInt::operator=(const std::string& s) +{ + //PROFINY_SCOPE + fromString(s); + return *this; +} + +inline const InfInt& InfInt::operator=(int l) +{ + //PROFINY_SCOPE + bool subtractOne = false; + if (l == INT_MIN) + { + subtractOne = true; + ++l; + } + + pos = l >= 0; + val.clear(); + if (!pos) + { + l = -l; + } + do + { + div_t dt = my_div(l, BASE); + val.push_back((ELEM_TYPE) dt.rem); + l = dt.quot; + } while (l > 0); + + return subtractOne ? --*this : *this; +} + +inline const InfInt& InfInt::operator=(long l) +{ + //PROFINY_SCOPE + bool subtractOne = false; + if (l == LONG_MIN) + { + subtractOne = true; + ++l; + } + + pos = l >= 0; + val.clear(); + if (!pos) + { + l = -l; + } + do + { + ldiv_t dt = my_ldiv(l, BASE); + val.push_back((ELEM_TYPE) dt.rem); + l = dt.quot; + } while (l > 0); + + return subtractOne ? --*this : *this; +} + +inline const InfInt& InfInt::operator=(long long l) +{ + //PROFINY_SCOPE + bool subtractOne = false; + if (l == LONG_LONG_MIN) + { + subtractOne = true; + ++l; + } + + pos = l >= 0; + val.clear(); + if (!pos) + { + l = -l; + } + do + { + lldiv_t dt = my_lldiv(l, BASE); + val.push_back((ELEM_TYPE) dt.rem); + l = dt.quot; + } while (l > 0); + + return subtractOne ? --*this : *this; +} + +inline const InfInt& InfInt::operator=(unsigned int l) +{ + //PROFINY_SCOPE + pos = true; + val.clear(); + do + { + val.push_back((ELEM_TYPE) (l % BASE)); + l = l / BASE; + } while (l > 0); + return *this; +} + +inline const InfInt& InfInt::operator=(unsigned long l) +{ + //PROFINY_SCOPE + pos = true; + val.clear(); + do + { + val.push_back((ELEM_TYPE) (l % BASE)); + l = l / BASE; + } while (l > 0); + return *this; +} + +inline const InfInt& InfInt::operator=(unsigned long long l) +{ + //PROFINY_SCOPE + pos = true; + val.clear(); + do + { + val.push_back((ELEM_TYPE) (l % BASE)); + l = l / BASE; + } while (l > 0); + return *this; +} + +inline const InfInt& InfInt::operator=(const InfInt& l) +{ + //PROFINY_SCOPE + pos = l.pos; + val = l.val; + return *this; +} + +inline const InfInt& InfInt::operator++() +{ + //PROFINY_SCOPE + val[0] += (pos ? 1 : -1); + this->correct(false, true); + return *this; +} + +inline const InfInt& InfInt::operator--() +{ + //PROFINY_SCOPE + val[0] -= (pos ? 1 : -1); + this->correct(false, true); + return *this; +} + +inline InfInt InfInt::operator++(int) +{ + //PROFINY_SCOPE + InfInt result = *this; + val[0] += (pos ? 1 : -1); + this->correct(false, true); + return result; +} + +inline InfInt InfInt::operator--(int) +{ + //PROFINY_SCOPE + InfInt result = *this; + val[0] -= (pos ? 1 : -1); + this->correct(false, true); + return result; +} + +inline const InfInt& InfInt::operator+=(const InfInt& rhs) +{ + //PROFINY_SCOPE + if (rhs.val.size() > val.size()) + { + val.resize(rhs.val.size(), 0); + } + for (size_t i = 0; i < val.size(); ++i) + { + val[i] = (pos ? val[i] : -val[i]) + (i < rhs.val.size() ? (rhs.pos ? rhs.val[i] : -rhs.val[i]) : 0); + } + correct(); + return *this; +} + +inline const InfInt& InfInt::operator-=(const InfInt& rhs) +{ + //PROFINY_SCOPE + if (rhs.val.size() > val.size()) + { + val.resize(rhs.val.size(), 0); + } + for (size_t i = 0; i < val.size(); ++i) + { + val[i] = (pos ? val[i] : -val[i]) - (i < rhs.val.size() ? (rhs.pos ? rhs.val[i] : -rhs.val[i]) : 0); + } + correct(); + return *this; +} + +inline const InfInt& InfInt::operator*=(const InfInt& rhs) +{ + //PROFINY_SCOPE + // TODO: optimize (do not use operator*) + *this = *this * rhs; + return *this; +} + +inline const InfInt& InfInt::operator/=(const InfInt& rhs) +{ + //PROFINY_SCOPE + if (rhs == 0) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("division by zero"); +#else + std::cerr << "Division by zero!" << std::endl; + return *this; +#endif + } + InfInt R, D = (rhs.pos ? rhs : -rhs), N = (pos ? *this : -*this); + bool oldpos = pos; + std::fill(val.begin(), val.end(), 0); + for (int i = (int) N.val.size() - 1; i >= 0; --i) + { + R.val.insert(R.val.begin(), N.val[i]); + R.correct(true); + ELEM_TYPE cnt = dInR(R, D); + R -= D * cnt; + val[i] += cnt; + } + correct(); + pos = (val.size() == 1 && val[0] == 0) ? true : (oldpos == rhs.pos); + return *this; +} + +inline const InfInt& InfInt::operator%=(const InfInt& rhs) +{ + //PROFINY_SCOPE + // TODO: optimize (do not use operator%) + *this = *this % rhs; + return *this; +// if (rhs == 0) +// { +//#ifdef INFINT_USE_EXCEPTIONS +// throw InfIntException("division by zero"); +//#else +// std::cerr << "Division by zero!" << std::endl; +// return *this; +//#endif +// } +// InfInt D = (rhs.pos ? rhs : -rhs), N = (pos ? *this : -*this); +// bool oldpos = pos; +// val.clear(); +// for (int i = (int) N.val.size() - 1; i >= 0; --i) +// { +// val.insert(val.begin(), N.val[i]); +// correct(true); +// *this -= D * dInR(*this, D); +// } +// correct(); +// pos = (val.size() == 1 && val[0] == 0) ? true : oldpos; +// return *this; +} + +inline const InfInt& InfInt::operator*=(ELEM_TYPE rhs) +{ + //PROFINY_SCOPE + ELEM_TYPE factor = rhs < 0 ? -rhs : rhs; + bool oldpos = pos; + multiplyByDigit(factor, val); + correct(); + pos = (val.size() == 1 && val[0] == 0) ? true : (oldpos == (rhs >= 0)); + return *this; +} + +inline InfInt InfInt::operator-() const +{ + //PROFINY_SCOPE + InfInt result = *this; + result.pos = !pos; + return result; +} + +inline InfInt InfInt::operator+(const InfInt& rhs) const +{ + //PROFINY_SCOPE + InfInt result; + result.val.resize(val.size() > rhs.val.size() ? val.size() : rhs.val.size(), 0); + for (size_t i = 0; i < val.size() || i < rhs.val.size(); ++i) + { + result.val[i] = (i < val.size() ? (pos ? val[i] : -val[i]) : 0) + (i < rhs.val.size() ? (rhs.pos ? rhs.val[i] : -rhs.val[i]) : 0); + } + result.correct(); + return result; +} + +inline InfInt InfInt::operator-(const InfInt& rhs) const +{ + //PROFINY_SCOPE + InfInt result; + result.val.resize(val.size() > rhs.val.size() ? val.size() : rhs.val.size(), 0); + for (size_t i = 0; i < val.size() || i < rhs.val.size(); ++i) + { + result.val[i] = (i < val.size() ? (pos ? val[i] : -val[i]) : 0) - (i < rhs.val.size() ? (rhs.pos ? rhs.val[i] : -rhs.val[i]) : 0); + } + result.correct(); + return result; +} + +inline InfInt InfInt::operator*(const InfInt& rhs) const +{ + //PROFINY_SCOPE + InfInt result; + result.val.resize(val.size() + rhs.val.size(), 0); + PRODUCT_TYPE carry = 0; + size_t digit = 0; + for (;; ++digit) + { + lldiv_t dt = my_lldiv(carry, BASE); + carry = dt.quot; + result.val[digit] = (ELEM_TYPE) dt.rem; + + bool found = false; + for (size_t i = digit < rhs.val.size() ? 0 : digit - rhs.val.size() + 1; i < val.size() && i <= digit; ++i) + { + PRODUCT_TYPE pval = result.val[digit] + val[i] * (PRODUCT_TYPE) rhs.val[digit - i]; + if (pval >= BASE || pval <= -BASE) + { + lldiv_t dt = my_lldiv(pval, BASE); + carry += dt.quot; + pval = dt.rem; + } + result.val[digit] = (ELEM_TYPE) pval; + found = true; + } + if (!found) + { + break; + } + } + for (; carry > 0; ++digit) + { + lldiv_t dt = my_lldiv(carry, BASE); + result.val[digit] = (ELEM_TYPE) dt.rem; + carry = dt.quot; + } + result.correct(); + result.pos = (result.val.size() == 1 && result.val[0] == 0) ? true : (pos == rhs.pos); + return result; +} + +inline InfInt InfInt::operator/(const InfInt& rhs) const +{ + //PROFINY_SCOPE + if (rhs == 0) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("division by zero"); +#else + std::cerr << "Division by zero!" << std::endl; + return 0; +#endif + } + InfInt Q, R, D = (rhs.pos ? rhs : -rhs), N = (pos ? *this : -*this); + Q.val.resize(N.val.size(), 0); + for (int i = (int) N.val.size() - 1; i >= 0; --i) + { + R.val.insert(R.val.begin(), N.val[i]); + R.correct(true); + ELEM_TYPE cnt = dInR(R, D); + R -= D * cnt; + Q.val[i] += cnt; + } + Q.correct(); + Q.pos = (Q.val.size() == 1 && Q.val[0] == 0) ? true : (pos == rhs.pos); + return Q; +} + +inline InfInt InfInt::operator%(const InfInt& rhs) const +{ + //PROFINY_SCOPE + if (rhs == 0) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("division by zero"); +#else + std::cerr << "Division by zero!" << std::endl; + return 0; +#endif + } + InfInt R, D = (rhs.pos ? rhs : -rhs), N = (pos ? *this : -*this); + for (int i = (int) N.val.size() - 1; i >= 0; --i) + { + R.val.insert(R.val.begin(), N.val[i]); + R.correct(true); + R -= D * dInR(R, D); + } + R.correct(); + R.pos = (R.val.size() == 1 && R.val[0] == 0) ? true : pos; + return R; +} + +inline InfInt InfInt::operator*(ELEM_TYPE rhs) const +{ + //PROFINY_SCOPE + InfInt result = *this; + ELEM_TYPE factor = rhs < 0 ? -rhs : rhs; + multiplyByDigit(factor, result.val); + result.correct(); + result.pos = (result.val.size() == 1 && result.val[0] == 0) ? true : (pos == (rhs >= 0)); + return result; +} + +inline bool InfInt::operator==(const InfInt& rhs) const +{ + //PROFINY_SCOPE + if (pos != rhs.pos || val.size() != rhs.val.size()) + { + return false; + } + for (int i = (int) val.size() - 1; i >= 0; --i) + { + if (val[i] != rhs.val[i]) + { + return false; + } + } + return true; +} + +inline bool InfInt::operator!=(const InfInt& rhs) const +{ + //PROFINY_SCOPE + if (pos != rhs.pos || val.size() != rhs.val.size()) + { + return true; + } + for (int i = (int) val.size() - 1; i >= 0; --i) + { + if (val[i] != rhs.val[i]) + { + return true; + } + } + return false; +} + +inline bool InfInt::operator<(const InfInt& rhs) const +{ + //PROFINY_SCOPE + if (pos && !rhs.pos) + { + return false; + } + if (!pos && rhs.pos) + { + return true; + } + if (val.size() > rhs.val.size()) + { + return pos ? false : true; + } + if (val.size() < rhs.val.size()) + { + return pos ? true : false; + } + for (int i = (int) val.size() - 1; i >= 0; --i) + { + if (val[i] < rhs.val[i]) + { + return pos ? true : false; + } + if (val[i] > rhs.val[i]) + { + return pos ? false : true; + } + } + return false; +} + +inline bool InfInt::operator<=(const InfInt& rhs) const +{ + //PROFINY_SCOPE + if (pos && !rhs.pos) + { + return false; + } + if (!pos && rhs.pos) + { + return true; + } + if (val.size() > rhs.val.size()) + { + return pos ? false : true; + } + if (val.size() < rhs.val.size()) + { + return pos ? true : false; + } + for (int i = (int) val.size() - 1; i >= 0; --i) + { + if (val[i] < rhs.val[i]) + { + return pos ? true : false; + } + if (val[i] > rhs.val[i]) + { + return pos ? false : true; + } + } + return true; +} + +inline bool InfInt::operator>(const InfInt& rhs) const +{ + //PROFINY_SCOPE + if (pos && !rhs.pos) + { + return true; + } + if (!pos && rhs.pos) + { + return false; + } + if (val.size() > rhs.val.size()) + { + return pos ? true : false; + } + if (val.size() < rhs.val.size()) + { + return pos ? false : true; + } + for (int i = (int) val.size() - 1; i >= 0; --i) + { + if (val[i] < rhs.val[i]) + { + return pos ? false : true; + } + if (val[i] > rhs.val[i]) + { + return pos ? true : false; + } + } + return false; +} + +inline bool InfInt::operator>=(const InfInt& rhs) const +{ + //PROFINY_SCOPE + if (pos && !rhs.pos) + { + return true; + } + if (!pos && rhs.pos) + { + return false; + } + if (val.size() > rhs.val.size()) + { + return pos ? true : false; + } + if (val.size() < rhs.val.size()) + { + return pos ? false : true; + } + for (int i = (int) val.size() - 1; i >= 0; --i) + { + if (val[i] < rhs.val[i]) + { + return pos ? false : true; + } + if (val[i] > rhs.val[i]) + { + return pos ? true : false; + } + } + return true; +} + +inline void InfInt::optimizeSqrtSearchBounds(InfInt& lo, InfInt& hi) const +{ + //PROFINY_SCOPE + InfInt hdn = 1; + for (int i = (int) this->numberOfDigits() / 2; i >= 2; --i) + { + hdn *= 10; + } + if (lo < hdn) + { + lo = hdn; + } + hdn *= 100; + if (hi > hdn) + { + hi = hdn; + } +} + +inline InfInt InfInt::intSqrt() const +{ + //PROFINY_SCOPE + if (*this <= 0) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("intSqrt called for non-positive integer"); +#else + std::cerr << "intSqrt called for non-positive integer: " << *this << std::endl; + return 0; +#endif + } + InfInt hi = *this / 2 + 1, lo = 0, mid, mid2; + optimizeSqrtSearchBounds(lo, hi); + do + { + mid = (hi + lo) / 2; // 8 factor + mid2 = mid * mid; // 1 factor + if (mid2 == *this) + { + lo = mid; + break; + } + else if (mid2 < *this) + { + lo = mid; + } + else + { + hi = mid; + } + } while (lo < hi - 1 && mid2 != *this); + return lo; +} + +inline char InfInt::digitAt(size_t i) const +{ + //PROFINY_SCOPE + if (numberOfDigits() <= i) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("invalid digit index"); +#else + std::cerr << "Invalid digit index: " << i << std::endl; + return -1; +#endif + } + return (val[i / DIGIT_COUNT] / powersOfTen[i % DIGIT_COUNT]) % 10; +} + +inline size_t InfInt::numberOfDigits() const +{ + //PROFINY_SCOPE + return (val.size() - 1) * DIGIT_COUNT + + (val.back() > 99999999 ? 9 : (val.back() > 9999999 ? 8 : (val.back() > 999999 ? 7 : (val.back() > 99999 ? 6 : + (val.back() > 9999 ? 5 : (val.back() > 999 ? 4 : (val.back() > 99 ? 3 : (val.back() > 9 ? 2 : 1)))))))); +} + +inline std::string InfInt::toString() const +{ + //PROFINY_SCOPE + std::ostringstream oss; + oss << *this; + return oss.str(); +} + +inline size_t InfInt::size() const +{ + //PROFINY_SCOPE + return val.size() * sizeof(ELEM_TYPE) + sizeof(bool); +} + +inline int InfInt::toInt() const +{ + //PROFINY_SCOPE + if (*this > INT_MAX || *this < INT_MIN) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("out of bounds"); +#else + std::cerr << "Out of INT bounds: " << *this << std::endl; +#endif + } + int result = 0; + for (int i = (int) val.size() - 1; i >= 0; --i) + { + result = result * BASE + val[i]; + } + return pos ? result : -result; +} + +inline long InfInt::toLong() const +{ + //PROFINY_SCOPE + if (*this > LONG_MAX || *this < LONG_MIN) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("out of bounds"); +#else + std::cerr << "Out of LONG bounds: " << *this << std::endl; +#endif + } + long result = 0; + for (int i = (int) val.size() - 1; i >= 0; --i) + { + result = result * BASE + val[i]; + } + return pos ? result : -result; +} + +inline long long InfInt::toLongLong() const +{ + //PROFINY_SCOPE + if (*this > LONG_LONG_MAX || *this < LONG_LONG_MIN) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("out of bounds"); +#else + std::cerr << "Out of LLONG bounds: " << *this << std::endl; +#endif + } + long long result = 0; + for (int i = (int) val.size() - 1; i >= 0; --i) + { + result = result * BASE + val[i]; + } + return pos ? result : -result; +} + +inline unsigned int InfInt::toUnsignedInt() const +{ + //PROFINY_SCOPE + if (!pos || *this > UINT_MAX) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("out of bounds"); +#else + std::cerr << "Out of UINT bounds: " << *this << std::endl; +#endif + } + unsigned int result = 0; + for (int i = (int) val.size() - 1; i >= 0; --i) + { + result = result * BASE + val[i]; + } + return result; +} + +inline unsigned long InfInt::toUnsignedLong() const +{ + //PROFINY_SCOPE + if (!pos || *this > ULONG_MAX) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("out of bounds"); +#else + std::cerr << "Out of ULONG bounds: " << *this << std::endl; +#endif + } + unsigned long result = 0; + for (int i = (int) val.size() - 1; i >= 0; --i) + { + result = result * BASE + val[i]; + } + return result; +} + +inline unsigned long long InfInt::toUnsignedLongLong() const +{ + //PROFINY_SCOPE + if (!pos || *this > ULONG_LONG_MAX) + { +#ifdef INFINT_USE_EXCEPTIONS + throw InfIntException("out of bounds"); +#else + std::cerr << "Out of ULLONG bounds: " << *this << std::endl; +#endif + } + unsigned long long result = 0; + for (int i = (int) val.size() - 1; i >= 0; --i) + { + result = result * BASE + val[i]; + } + return result; +} + +inline void InfInt::truncateToBase() +{ + //PROFINY_SCOPE + for (size_t i = 0; i < val.size(); ++i) // truncate each + { + if (val[i] >= BASE || val[i] <= -BASE) + { + div_t dt = my_div(val[i], BASE); + val[i] = dt.rem; + if (i + 1 >= val.size()) + { + val.push_back(dt.quot); + } + else + { + val[i + 1] += dt.quot; + } + } + } +} + +inline bool InfInt::equalizeSigns() +{ + //PROFINY_SCOPE + bool isPositive = true; + int i = (int) ((val.size())) - 1; + for (; i >= 0; --i) + { + if (val[i] != 0) + { + isPositive = val[i--] > 0; + break; + } + } + + if (isPositive) + { + for (; i >= 0; --i) + { + if (val[i] < 0) + { + int k = 0, index = i + 1; + for (; (size_t)(index) < val.size() && val[index] == 0; ++k, ++index) + ; // count adjacent zeros on left + //if ((size_t)(index) < val.size() && val[index] > 0) + { // number on the left is positive + val[index] -= 1; + val[i] += BASE; + for (; k > 0; --k) + { + val[i + k] = UPPER_BOUND; + } + } + } + } + } + else + { + for (; i >= 0; --i) + { + if (val[i] > 0) + { + int k = 0, index = i + 1; + for (; (size_t)(index) < val.size() && val[index] == 0; ++k, ++index) + ; // count adjacent zeros on right + //if ((size_t)(index) < val.size() && val[index] < 0) + { // number on the left is negative + val[index] += 1; + val[i] -= BASE; + for (; k > 0; --k) + { + val[i + k] = -UPPER_BOUND; + } + } + } + } + } + + return isPositive; +} + +inline void InfInt::removeLeadingZeros() +{ + //PROFINY_SCOPE + for (int i = (int) (val.size()) - 1; i > 0; --i) // remove leading 0's + { + if (val[i] != 0) + { + return; + } + else + { + val.erase(val.begin() + i); + } + } +} + +inline void InfInt::correct(bool justCheckLeadingZeros, bool hasValidSign) +{ + //PROFINY_SCOPE + if (!justCheckLeadingZeros) + { + truncateToBase(); + + if (equalizeSigns()) + { + pos = ((val.size() == 1 && val[0] == 0) || !hasValidSign) ? true : pos; + } + else + { + pos = hasValidSign ? !pos : false; + for (size_t i = 0; i < val.size(); ++i) + { + val[i] = abs(val[i]); + } + } + } + + removeLeadingZeros(); +} + +inline void InfInt::fromString(const std::string& s) +{ + //PROFINY_SCOPE + pos = true; + val.clear(); + val.reserve(s.size() / DIGIT_COUNT + 1); + int i = (int) s.size() - DIGIT_COUNT; + for (; i >= 0; i -= DIGIT_COUNT) + { + val.push_back(atoi(s.substr(i, DIGIT_COUNT).c_str())); + } + if (i > -DIGIT_COUNT) + { + std::string ss = s.substr(0, i + DIGIT_COUNT); + if (ss.size() == 1 && ss[0] == '-') + { + pos = false; + } + else + { + val.push_back(atoi(ss.c_str())); + } + } + if (val.back() < 0) + { + val.back() = -val.back(); + pos = false; + } + correct(true); +} + +inline ELEM_TYPE InfInt::dInR(const InfInt& R, const InfInt& D) +{ + //PROFINY_SCOPE + ELEM_TYPE min = 0, max = UPPER_BOUND; + while (max > min) + { + ELEM_TYPE avg = max + min; + div_t dt = my_div(avg, 2); + avg = dt.rem ? (dt.quot + 1) : dt.quot; + InfInt prod = D * avg; + if (R == prod) + { + return avg; + } + else if (R > prod) + { + min = avg; + } + else + { + max = avg - 1; + } + } + return min; +} + +inline void InfInt::multiplyByDigit(ELEM_TYPE factor, std::vector& val) +{ + //PROFINY_SCOPE + ELEM_TYPE carry = 0; + for (size_t i = 0; i < val.size(); ++i) + { + PRODUCT_TYPE pval = val[i] * (PRODUCT_TYPE) factor + carry; + if (pval >= BASE || pval <= -BASE) + { + lldiv_t dt = my_lldiv(pval, BASE); + carry = (ELEM_TYPE) dt.quot; + pval = dt.rem; + } + else + { + carry = 0; + } + val[i] = (ELEM_TYPE) pval; + } + if (carry > 0) + { + val.push_back(carry); + } +} + +/**************************************************************/ +/******************** NON-MEMBER OPERATORS ********************/ +/**************************************************************/ + +inline std::istream& operator>>(std::istream &s, InfInt &n) +{ + //PROFINY_SCOPE + std::string str; + s >> str; + n.fromString(str); + return s; +} + +inline std::ostream& operator<<(std::ostream &s, const InfInt &n) +{ + //PROFINY_SCOPE + if (!n.pos) + { + s << '-'; + } + bool first = true; + for (int i = (int) n.val.size() - 1; i >= 0; --i) + { + if (first) + { + s << n.val[i]; + first = false; + } + else + { + s << std::setfill('0') << std::setw(DIGIT_COUNT) << n.val[i]; + } + } + return s; +} + +#endif diff --git a/libraries/fc/vendor/rlpvalue/src/rlp2json.cpp b/libraries/fc/vendor/rlpvalue/src/rlp2json.cpp new file mode 100644 index 00000000..c50ede3c --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/src/rlp2json.cpp @@ -0,0 +1,107 @@ + +#include +#include +#include "rlpvalue.h" +#include "InfInt.h" + +extern void RLPtoJSON(const RLPValue& rval, UniValue& jval); +extern std::string encodeBinary(uint64_t n); + +static void assignJsonArray(UniValue& jval, const RLPValue& rval) +{ + jval.setArray(); + + const std::vector& values = rval.getValues(); + for (auto it = values.begin(); it != values.end(); it++) { + const RLPValue& childVal = *it; + UniValue childJval; + + RLPtoJSON(childVal, childJval); + + jval.push_back(childJval); + } +} + +static void assignJsonBuffer(UniValue& jval, const RLPValue& rval) +{ + jval.setStr(rval.getValStr()); +} + +void RLPtoJSON(const RLPValue& rval, UniValue& jval) +{ + if (rval.isBuffer()) + assignJsonBuffer(jval, rval); + else + assignJsonArray(jval, rval); +} + +static bool isBigNumStr(const std::string& s) +{ + // first char must be # + if (s.empty() || s[0] != '#') + return false; + + // remaining chars must be digits + for (unsigned int i = 1; i < s.size(); i++) + if (!isdigit(s[i])) + return false; + + return true; +} + +static std::string encodeBigNum(const InfInt& n) +{ + std::string rs; + + if (n == 0) { + // do nothing; return empty string + } else { + rs.assign(encodeBigNum(n / 256)); + + InfInt iich = n % 256; + unsigned char ch = iich.toUnsignedLong(); + rs.append((const char *) &ch, 1); + } + + return rs; +} + +static std::string encodeBigNumStr(const std::string& s) +{ + InfInt n(s); + return encodeBigNum(n); +} + +bool JSONtoRLP(const UniValue& jval, RLPValue& rval) +{ + if (jval.isStr()) { + std::string ins = jval.getValStr(); + if (isBigNumStr(ins)) + ins = encodeBigNumStr(ins.substr(1)); + + rval.assign(ins); + return true; + } + + if (jval.isNum()) { + uint64_t val = jval.get_int64(); + std::string val_enc = encodeBinary(val); + rval.assign(val_enc); + return true; + } + + if (jval.isArray()) { + rval.setArray(); + const std::vector& arrVals = jval.getValues(); + for (auto it = arrVals.begin(); it != arrVals.end(); it++) { + const UniValue& childJval = *it; + RLPValue tmp; + if (!JSONtoRLP(childJval, tmp)) + return false; + rval.push_back(tmp); + } + return true; + } + + return false; +} diff --git a/libraries/fc/vendor/rlpvalue/src/tool.cpp b/libraries/fc/vendor/rlpvalue/src/tool.cpp new file mode 100644 index 00000000..d17158e7 --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/src/tool.cpp @@ -0,0 +1,189 @@ + +/* + * Copyright 2019 Bloq Inc. + * + */ + +#ifndef HAVE_CONFIG_H +#error missing autoconf-generated config.h. +#endif +#include "rlpvalue-config.h" + +#include +#include +#include +#include +#include "rlpvalue.h" +#include "../test/utilstrencodings.h" + +using namespace std; + +extern void RLPtoJSON(const RLPValue& rval, UniValue& jval); +extern bool JSONtoRLP(const UniValue& jval, RLPValue& rval); + +static const char doc[] = +"rlp - encode or decode RLP protocol encoding"; + +static struct argp_option options[] = { + { "decode", 'd', NULL, 0, + "Decode RLP to JSON" }, + { "encode", 'e', NULL, 0, + "Encode JSON to RLP (default)" }, + { } +}; + +static error_t parse_opt (int key, char *arg, struct argp_state *state); +static const struct argp argp = { options, parse_opt, NULL, doc }; + +static bool opt_decode = false; +static bool inp_json, inp_rlp, outp_json, outp_rlp; +static vector file_args; +static UniValue global_jval; +static RLPValue global_rval; + +static error_t parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) { + case 'd': opt_decode = true; break; + case 'e': opt_decode = false; break; + + case ARGP_KEY_ARG: + file_args.push_back(arg); + break; + + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + +static bool parseJsonInput(const std::string& body) +{ + bool rc = global_jval.read(body); + + if (!rc) + fprintf(stderr, "JSON input validation failed\n"); + + return rc; +} + +static bool parseRlpInput(const std::string& body) +{ + std::vector buf; + + if (body.substr(0, 2) == "0x") { + string tmp = body.substr(2); + buf = ParseHex(tmp); + } else + buf = ParseHex(body); + + size_t consumed, wanted; + bool rc = global_rval.read(&buf[0], buf.size(), consumed, wanted); + + if (!rc) + fprintf(stderr, "RLP input validation failed (%zu wanted)\n", + wanted); + + return rc; +} + +static bool readInput() +{ + if (opt_decode) { + inp_json = false; + inp_rlp = true; + outp_json = true; + outp_rlp = false; + } else { + inp_json = true; + inp_rlp = false; + outp_json = false; + outp_rlp = true; + } + + const char *filename = nullptr; + FILE *inf; + if (file_args.empty()) { + filename = "(standard input)"; + inf = stdin; + } else { + filename = file_args[0].c_str(); + inf = ::fopen(filename, "r"); + if (!inf) { + perror(filename); + return false; + } + } + + string body; + + while (1) { + vector buf(4096); + size_t rrc = fread(&buf[0], 1, buf.size(), inf); + body.append((char *) &buf[0], rrc); + if (rrc < buf.size()) + break; + } + bool haveErr = ferror(inf); + if (inf != stdin) + fclose(inf); + + if (haveErr) { + perror(filename); + return false; + } + + if (inp_json) + return parseJsonInput(body); + else + return parseRlpInput(body); +} + +static bool mutateInput() +{ + if (inp_rlp) + RLPtoJSON(global_rval, global_jval); + else + JSONtoRLP(global_jval, global_rval); + return true; +} + +static bool writeJsonOutput() +{ + string body = global_jval.write(2); + printf("%s\n", body.c_str()); + return true; +} + +static bool writeRlpOutput() +{ + string body = global_rval.write(); + string hex = HexStr(body.begin(), body.end()); + printf("%s\n", hex.c_str()); + return true; +} + +static bool writeOutput() +{ + if (outp_json) + return writeJsonOutput(); + else + return writeRlpOutput(); +} + +int main (int argc, char *argv[]) +{ + error_t argp_rc = argp_parse(&argp, argc, argv, 0, NULL, NULL); + if (argp_rc) { + fprintf(stderr, "%s: argp_parse failed: %s\n", + argv[0], strerror(argp_rc)); + return EXIT_FAILURE; + } + + if (!readInput() || !mutateInput() || !writeOutput()) + return 1; + + return 0; +} + diff --git a/libraries/fc/vendor/rlpvalue/test/.gitignore b/libraries/fc/vendor/rlpvalue/test/.gitignore new file mode 100644 index 00000000..7b27cf0d --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/test/.gitignore @@ -0,0 +1,8 @@ + +object +unitester +test_json +no_nul + +*.trs +*.log diff --git a/libraries/fc/vendor/rlpvalue/test/data/example.json b/libraries/fc/vendor/rlpvalue/test/data/example.json new file mode 100644 index 00000000..e395204d --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/test/data/example.json @@ -0,0 +1,6 @@ +{ + "listsoflists2": { + "in": "VALID", + "out": "c7c0c1c0c3c0c1c0" + } +} diff --git a/libraries/fc/vendor/rlpvalue/test/data/invalidRLPTest.json b/libraries/fc/vendor/rlpvalue/test/data/invalidRLPTest.json new file mode 100644 index 00000000..1f9b806c --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/test/data/invalidRLPTest.json @@ -0,0 +1,46 @@ +{ + "int32Overflow": { + "in": "INVALID", + "out": "bf0f000000000000021111" + }, + + "int32Overflow2": { + "in": "INVALID", + "out": "ff0f000000000000021111" + }, + + "wrongSizeList": { + "in": "INVALID", + "out": "f80180" + }, + + "wrongSizeList2": { + "in": "INVALID", + "out": "f80100" + }, + + "incorrectLengthInArray": { + "in": "INVALID", + "out": "b9002100dc2b275d0f74e8a53e6f4ec61b27f24278820be3f82ea2110e582081b0565df0" + }, + + "randomRLP": { + "in": "INVALID", + "out": "f861f83eb9002100dc2b275d0f74e8a53e6f4ec61b27f24278820be3f82ea2110e582081b0565df027b90015002d5ef8325ae4d034df55d4b58d0dfba64d61ddd17be00000b9001a00dae30907045a2f66fa36f2bb8aa9029cbb0b8a7b3b5c435ab331" + }, + + "bytesShouldBeSingleByte00": { + "in": "INVALID", + "out": "8100" + }, + + "bytesShouldBeSingleByte01": { + "in": "INVALID", + "out": "8101" + }, + + "bytesShouldBeSingleByte7F": { + "in": "INVALID", + "out": "817F" + } +} diff --git a/libraries/fc/vendor/rlpvalue/test/data/longlist.json b/libraries/fc/vendor/rlpvalue/test/data/longlist.json new file mode 100644 index 00000000..525fe167 --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/test/data/longlist.json @@ -0,0 +1,48 @@ +{ + "longList1" : { + "in" : [ + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"] + ], + "out": "0xf840cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376" + }, + "longList2" : { + "in" : [ + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"], + ["asdf","qwer","zxcv"] + ], + "out": "0xf90200cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376cf84617364668471776572847a786376" + } +} diff --git a/libraries/fc/vendor/rlpvalue/test/data/rlptest.json b/libraries/fc/vendor/rlpvalue/test/data/rlptest.json new file mode 100644 index 00000000..725022de --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/test/data/rlptest.json @@ -0,0 +1,111 @@ +{ + "emptystring": { + "in": "", + "out": "0x80" + }, + "bytestring00": { + "in": "\u0000", + "out": "0x00" + }, + "bytestring01": { + "in": "\u0001", + "out": "0x01" + }, + "bytestring7F": { + "in": "\u007F", + "out": "0x7f" + }, + "shortstring": { + "in": "dog", + "out": "0x83646f67" + }, + "shortstring2": { + "in": "Lorem ipsum dolor sit amet, consectetur adipisicing eli", + "out": "0xb74c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e7365637465747572206164697069736963696e6720656c69" + }, + "longstring": { + "in": "Lorem ipsum dolor sit amet, consectetur adipisicing elit", + "out": "0xb8384c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e7365637465747572206164697069736963696e6720656c6974" + }, + "longstring2": { + "in": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur mauris magna, suscipit sed vehicula non, iaculis faucibus tortor. Proin suscipit ultricies malesuada. Duis tortor elit, dictum quis tristique eu, ultrices at risus. Morbi a est imperdiet mi ullamcorper aliquet suscipit nec lorem. Aenean quis leo mollis, vulputate elit varius, consequat enim. Nulla ultrices turpis justo, et posuere urna consectetur nec. Proin non convallis metus. Donec tempor ipsum in mauris congue sollicitudin. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse convallis sem vel massa faucibus, eget lacinia lacus tempor. Nulla quis ultricies purus. Proin auctor rhoncus nibh condimentum mollis. Aliquam consequat enim at metus luctus, a eleifend purus egestas. Curabitur at nibh metus. Nam bibendum, neque at auctor tristique, lorem libero aliquet arcu, non interdum tellus lectus sit amet eros. Cras rhoncus, metus ac ornare cursus, dolor justo ultrices metus, at ullamcorper volutpat", + "out": "0xb904004c6f72656d20697073756d20646f6c6f722073697420616d65742c20636f6e73656374657475722061646970697363696e6720656c69742e20437572616269747572206d6175726973206d61676e612c20737573636970697420736564207665686963756c61206e6f6e2c20696163756c697320666175636962757320746f72746f722e2050726f696e20737573636970697420756c74726963696573206d616c6573756164612e204475697320746f72746f7220656c69742c2064696374756d2071756973207472697374697175652065752c20756c7472696365732061742072697375732e204d6f72626920612065737420696d70657264696574206d6920756c6c616d636f7270657220616c6971756574207375736369706974206e6563206c6f72656d2e2041656e65616e2071756973206c656f206d6f6c6c69732c2076756c70757461746520656c6974207661726975732c20636f6e73657175617420656e696d2e204e756c6c6120756c74726963657320747572706973206a7573746f2c20657420706f73756572652075726e6120636f6e7365637465747572206e65632e2050726f696e206e6f6e20636f6e76616c6c6973206d657475732e20446f6e65632074656d706f7220697073756d20696e206d617572697320636f6e67756520736f6c6c696369747564696e2e20566573746962756c756d20616e746520697073756d207072696d697320696e206661756369627573206f726369206c756374757320657420756c74726963657320706f737565726520637562696c69612043757261653b2053757370656e646973736520636f6e76616c6c69732073656d2076656c206d617373612066617563696275732c2065676574206c6163696e6961206c616375732074656d706f722e204e756c6c61207175697320756c747269636965732070757275732e2050726f696e20617563746f722072686f6e637573206e69626820636f6e64696d656e74756d206d6f6c6c69732e20416c697175616d20636f6e73657175617420656e696d206174206d65747573206c75637475732c206120656c656966656e6420707572757320656765737461732e20437572616269747572206174206e696268206d657475732e204e616d20626962656e64756d2c206e6571756520617420617563746f72207472697374697175652c206c6f72656d206c696265726f20616c697175657420617263752c206e6f6e20696e74657264756d2074656c6c7573206c65637475732073697420616d65742065726f732e20437261732072686f6e6375732c206d65747573206163206f726e617265206375727375732c20646f6c6f72206a7573746f20756c747269636573206d657475732c20617420756c6c616d636f7270657220766f6c7574706174" + }, + "zero": { + "in": 0, + "out": "0x80" + }, + "smallint": { + "in": 1, + "out": "0x01" + }, + "smallint2": { + "in": 16, + "out": "0x10" + }, + "smallint3": { + "in": 79, + "out": "0x4f" + }, + "smallint4": { + "in": 127, + "out": "0x7f" + }, + "mediumint1": { + "in": 128, + "out": "0x8180" + }, + "mediumint2": { + "in": 1000, + "out": "0x8203e8" + }, + "mediumint3": { + "in": 100000, + "out": "0x830186a0" + }, + "mediumint4": { + "in": "#83729609699884896815286331701780722", + "out": "0x8f102030405060708090a0b0c0d0e0f2" + }, + "mediumint5": { + "in": "#105315505618206987246253880190783558935785933862974822347068935681", + "out": "0x9c0100020003000400050006000700080009000a000b000c000d000e01" + }, + "emptylist": { + "in": [], + "out": "0xc0" + }, + "stringlist": { + "in": [ "dog", "god", "cat" ], + "out": "0xcc83646f6783676f6483636174" + }, + "multilist": { + "in": [ "zw", [ 4 ], 1 ], + "out": "0xc6827a77c10401" + }, + "shortListMax1": { + "in": [ "asdf", "qwer", "zxcv", "asdf","qwer", "zxcv", "asdf", "qwer", "zxcv", "asdf", "qwer"], + "out": "0xf784617364668471776572847a78637684617364668471776572847a78637684617364668471776572847a78637684617364668471776572" + }, + "listsoflists": { + "in": [ [ [], [] ], [] ], + "out": "0xc4c2c0c0c0" + }, + "listsoflists2": { + "in": [ [], [[]], [ [], [[]] ] ], + "out": "0xc7c0c1c0c3c0c1c0" + }, + "dictTest1" : { + "in" : [ + ["key1", "val1"], + ["key2", "val2"], + ["key3", "val3"], + ["key4", "val4"] + ], + "out" : "0xecca846b6579318476616c31ca846b6579328476616c32ca846b6579338476616c33ca846b6579348476616c34" + }, + "bigint": { + "in": "#115792089237316195423570985008687907853269984665640564039457584007913129639936", + "out": "0xa1010000000000000000000000000000000000000000000000000000000000000000" + } +} diff --git a/libraries/fc/vendor/rlpvalue/test/object.cpp b/libraries/fc/vendor/rlpvalue/test/object.cpp new file mode 100644 index 00000000..9918f659 --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/test/object.cpp @@ -0,0 +1,171 @@ +// Copyright (c) 2014 BitPay Inc. +// Copyright (c) 2014-2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include +#include +#include + +#define BOOST_FIXTURE_TEST_SUITE(a, b) +#define BOOST_AUTO_TEST_CASE(funcName) void funcName() +#define BOOST_AUTO_TEST_SUITE_END() +#define BOOST_CHECK(expr) assert(expr) +#define BOOST_CHECK_EQUAL(v1, v2) assert((v1) == (v2)) +#define BOOST_CHECK_THROW(stmt, excMatch) { \ + try { \ + (stmt); \ + assert(0 && "No exception caught"); \ + } catch (excMatch & e) { \ + } catch (...) { \ + assert(0 && "Wrong exception caught"); \ + } \ + } +#define BOOST_CHECK_NO_THROW(stmt) { \ + try { \ + (stmt); \ + } catch (...) { \ + assert(0); \ + } \ + } + +BOOST_FIXTURE_TEST_SUITE(rlpvalue_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(rlpvalue_constructor) +{ + RLPValue v2(RLPValue::VBUF); + BOOST_CHECK(v2.isBuffer()); + + RLPValue v3(RLPValue::VBUF); + v3.assign("foo"); + BOOST_CHECK(v3.isBuffer()); + BOOST_CHECK_EQUAL(v3.getValStr(), "foo"); + + std::string vs("yawn"); + RLPValue v8(vs); + BOOST_CHECK(v8.isBuffer()); + BOOST_CHECK_EQUAL(v8.getValStr(), "yawn"); + + const char *vcs = "zappa"; + RLPValue v9(vcs); + BOOST_CHECK(v9.isBuffer()); + BOOST_CHECK_EQUAL(v9.getValStr(), "zappa"); +} + +BOOST_AUTO_TEST_CASE(rlpvalue_set) +{ + RLPValue v("foo"); + v.clear(); + BOOST_CHECK_EQUAL(v.getValStr(), ""); + + BOOST_CHECK(v.setArray()); + BOOST_CHECK(v.isArray()); + BOOST_CHECK_EQUAL(v.size(), 0); + + v.assign("zum"); + BOOST_CHECK(v.isBuffer()); + BOOST_CHECK_EQUAL(v.getValStr(), "zum"); +} + +BOOST_AUTO_TEST_CASE(rlpvalue_array) +{ + RLPValue arr(RLPValue::VARR); + + std::string vStr("zippy"); + BOOST_CHECK(arr.push_back(vStr)); + + const char *s = "pippy"; + BOOST_CHECK(arr.push_back(s)); + + RLPValue v; + + std::vector vec; + v.assign("boing"); + vec.push_back(v); + + v.assign("going"); + vec.push_back(v); + + BOOST_CHECK(arr.push_backV(vec)); + + BOOST_CHECK_EQUAL(arr.empty(), false); + BOOST_CHECK_EQUAL(arr.size(), 4); + + BOOST_CHECK_EQUAL(arr[0].getValStr(), "zippy"); + BOOST_CHECK_EQUAL(arr[1].getValStr(), "pippy"); + BOOST_CHECK_EQUAL(arr[2].getValStr(), "boing"); + BOOST_CHECK_EQUAL(arr[3].getValStr(), "going"); + + BOOST_CHECK_EQUAL(arr[999].getValStr(), ""); + + arr.clear(); + BOOST_CHECK(arr.empty()); + BOOST_CHECK_EQUAL(arr.size(), 0); +} + +BOOST_AUTO_TEST_CASE(rlpvalue_readwrite) +{ + unsigned char s1[] = { 0x83, 'd', 'o', 'g' }; + + RLPValue v; + size_t consumed, wanted; + bool rc = v.read(&s1[0], sizeof(s1), consumed, wanted); + BOOST_CHECK(rc); + BOOST_CHECK(v.isBuffer()); + BOOST_CHECK_EQUAL(v.getValStr(), "dog"); + BOOST_CHECK_EQUAL(consumed, sizeof(s1)); + BOOST_CHECK_EQUAL(wanted, 0); + + std::string s1_out = v.write(); + BOOST_CHECK_EQUAL(sizeof(s1), s1_out.size()); + BOOST_CHECK_EQUAL(memcmp(&s1[0], &s1_out[0], sizeof(s1)), 0); + + unsigned char s2[] = + { 0xc8, 0x83, 'c', 'a', 't', 0x83, 'd', 'o', 'g' }; + + RLPValue v2; + rc = v2.read(&s2[0], sizeof(s2), consumed, wanted); + BOOST_CHECK(rc); + BOOST_CHECK(v2.isArray()); + BOOST_CHECK_EQUAL(consumed, sizeof(s2)); + BOOST_CHECK_EQUAL(wanted, 0); + BOOST_CHECK_EQUAL(v2[0].getValStr(), "cat"); + BOOST_CHECK_EQUAL(v2[1].getValStr(), "dog"); + + std::string s2_out = v2.write(); + BOOST_CHECK_EQUAL(sizeof(s2), s2_out.size()); + BOOST_CHECK_EQUAL(memcmp(&s2[0], &s2_out[0], sizeof(s2)), 0); + + unsigned char s_empty_list[] = { 0xc0 }; + RLPValue v_empty_list; + rc = v_empty_list.read(&s_empty_list[0], sizeof(s_empty_list), consumed, wanted); + BOOST_CHECK(rc); + BOOST_CHECK(v_empty_list.isArray()); + BOOST_CHECK_EQUAL(v_empty_list.size(), 0); + + unsigned char s_null[] = { 0x80 }; + RLPValue v_null; + rc = v_null.read(&s_null[0], sizeof(s_null), consumed, wanted); + BOOST_CHECK(rc); + BOOST_CHECK(v_null.isBuffer()); + BOOST_CHECK_EQUAL(v_null.getValStr(), ""); + BOOST_CHECK_EQUAL(consumed, sizeof(s_null)); + BOOST_CHECK_EQUAL(wanted, 0); +} + +BOOST_AUTO_TEST_SUITE_END() + +int main (int argc, char *argv[]) +{ + rlpvalue_constructor(); + rlpvalue_set(); + rlpvalue_array(); + rlpvalue_readwrite(); + return 0; +} + diff --git a/libraries/fc/vendor/rlpvalue/test/test_json.cpp b/libraries/fc/vendor/rlpvalue/test/test_json.cpp new file mode 100644 index 00000000..26828505 --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/test/test_json.cpp @@ -0,0 +1,24 @@ +// Test program that can be called by the JSON test suite at +// https://github.com/nst/JSONTestSuite. +// +// It reads JSON input from stdin and exits with code 0 if it can be parsed +// successfully. It also pretty prints the parsed JSON value to stdout. + +#include +#include +#include "rlpvalue.h" + +using namespace std; + +int main (int argc, char *argv[]) +{ + RLPValue val; + if (val.read(string(istreambuf_iterator(cin), + istreambuf_iterator()))) { + cout << val.write() << endl; + return 0; + } else { + cerr << "JSON Parse Error." << endl; + return 1; + } +} diff --git a/libraries/fc/vendor/rlpvalue/test/unitester.cpp b/libraries/fc/vendor/rlpvalue/test/unitester.cpp new file mode 100644 index 00000000..b487ff0e --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/test/unitester.cpp @@ -0,0 +1,207 @@ +// Copyright 2014 BitPay Inc. +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include +#include +#include "utilstrencodings.h" +#include "rlpvalue.h" +#include "../src/InfInt.h" + +using namespace std; + +#ifndef JSON_TEST_SRC +#error JSON_TEST_SRC must point to test source directory +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#endif + +std::string srcdir(JSON_TEST_SRC); +static bool test_failed = false; + +extern uint64_t toInteger(const unsigned char *raw, size_t len); +extern std::string encodeBinary(uint64_t n); +extern bool JSONtoRLP(const UniValue& jval, RLPValue& rval); + +static uint64_t toInteger(const char *raw, size_t len) { + return toInteger((const unsigned char *) raw, len); +} + +static bool isBigNumStr(const std::string& s) +{ + // first char must be # + if (s.empty() || s[0] != '#') + return false; + + // remaining chars must be digits + for (unsigned int i = 1; i < s.size(); i++) + if (!isdigit(s[i])) + return false; + + return true; +} + +static std::string encodeBigNum(const InfInt& n) +{ + std::string rs; + + if (n == 0) { + // do nothing; return empty string + } else { + rs.assign(encodeBigNum(n / 256)); + + InfInt iich = n % 256; + unsigned char ch = iich.toUnsignedLong(); + rs.append((const char *) &ch, 1); + } + + return rs; +} + +static std::string encodeBigNumStr(const std::string& s) +{ + InfInt n(s); + return encodeBigNum(n); +} + +static bool runtest(const std::string& filename, const std::string& key, + const UniValue& jval) +{ + if (!jval.isObject() || + !jval["out"].isStr()) { + fprintf(stderr, " %s: skipping test, invalid\n", + key.c_str()); + return true; + } + + string ins = jval["in"].getValStr(); + string outs = jval["out"].getValStr(); + + if (outs.substr(0, 2) == "0x") // remove 0x prefix + outs = outs.substr(2); + + // decode RLP binary output test string from hex to binary + std::vector outb = ParseHex(outs); + + // attempt to parse with RLP class + RLPValue v; + size_t consumed, wanted; + bool rrc = v.read(&outb[0], outb.size(), consumed, wanted); + + bool rc = false; + if (ins == "VALID" || ins == "INVALID") { + if (ins == "VALID" && rrc == true) + rc = true; + else if (ins == "INVALID" && rrc == false) + rc = true; + } else if (jval["in"].isStr()) { + if (isBigNumStr(ins)) + ins = encodeBigNumStr(ins.substr(1)); + + if (v.isBuffer() && (ins == v.getValStr())) + rc = true; + + } else if (jval["in"].isNum()) { + if (v.isBuffer()) { + uint64_t test_val = jval["in"].get_int64(); + string enc_val = v.getValStr(); + uint64_t dec_val = toInteger(&enc_val[0], + enc_val.size()); + if (test_val == dec_val) + rc = true; + } + } else if (jval["in"].isArray()) { + RLPValue root(RLPValue::VARR); + JSONtoRLP(jval["in"], root); + + std::string genOutput = root.write(); + if ((outb.size() == genOutput.size()) && + (memcmp(&outb[0], &genOutput[0], outb.size()) == 0)) { + rc = true; + } else { + std::string genHex = HexStr(genOutput.begin(), + genOutput.end()); + fprintf(stderr, "INS :%s\nGENS:%s\n", + outs.c_str(), + genHex.c_str()); + } + + } else { + fprintf(stderr, "ERR: test %s not implemented yet\n", key.c_str()); + } + + fprintf(stderr, " %s: %s\n", key.c_str(), + rc ? "ok" : "FAIL"); + return rc; +} + +static void runtest_jfile(std::string filename, const UniValue& jfile) +{ + assert(jfile.isObject()); + + const std::vector& keys = jfile.getKeys(); + + fprintf(stderr, "Running testfile %s (%zu tests)\n", + filename.c_str(), keys.size()); + + for (auto it = keys.begin(); it != keys.end(); it++) { + const std::string& key = *it; + if (!runtest(filename, key, jfile[key])) + test_failed = true; + } +} + +static void runtest_file(const char *filename_) +{ + std::string basename(filename_); + std::string filename = srcdir + "/" + basename; + FILE *f = fopen(filename.c_str(), "r"); + if (!f) { + perror(filename.c_str()); + exit(1); + } + + std::string jdata; + + char buf[4096]; + while (!feof(f)) { + int bread = fread(buf, 1, sizeof(buf), f); + assert(!ferror(f)); + + std::string s(buf, bread); + jdata += s; + } + + assert(!ferror(f)); + fclose(f); + + UniValue jfile; + bool rc = jfile.read(jdata); + assert(rc == true); + + runtest_jfile(basename, jfile); +} + +static const char *filenames[] = { + "example.json", + "invalidRLPTest.json", + "rlptest.json", +// "longlist.json", +}; + +int main (int argc, char *argv[]) +{ + for (unsigned int fidx = 0; fidx < ARRAY_SIZE(filenames); fidx++) { + runtest_file(filenames[fidx]); + } + + return test_failed ? 1 : 0; +} + diff --git a/libraries/fc/vendor/rlpvalue/test/utilstrencodings.cpp b/libraries/fc/vendor/rlpvalue/test/utilstrencodings.cpp new file mode 100644 index 00000000..901821c0 --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/test/utilstrencodings.cpp @@ -0,0 +1,226 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2017 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "utilstrencodings.h" + +#include +#include +#include +#include + +static const std::string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + +const signed char p_util_hexdigit[256] = +{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1, + -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, }; + +signed char HexDigit(char c) +{ + return p_util_hexdigit[(unsigned char)c]; +} + +bool IsHex(const std::string& str) +{ + for(std::string::const_iterator it(str.begin()); it != str.end(); ++it) + { + if (HexDigit(*it) < 0) + return false; + } + return (str.size() > 0) && (str.size()%2 == 0); +} + +bool IsHexNumber(const std::string& str) +{ + size_t starting_location = 0; + if (str.size() > 2 && *str.begin() == '0' && *(str.begin()+1) == 'x') { + starting_location = 2; + } + for (auto c : str.substr(starting_location)) { + if (HexDigit(c) < 0) return false; + } + // Return false for empty string or "0x". + return (str.size() > starting_location); +} + +std::vector ParseHex(const char* psz) +{ + // convert hex dump to vector + std::vector vch; + while (true) + { + while (isspace(*psz)) + psz++; + signed char c = HexDigit(*psz++); + if (c == (signed char)-1) + break; + unsigned char n = (c << 4); + c = HexDigit(*psz++); + if (c == (signed char)-1) + break; + n |= c; + vch.push_back(n); + } + return vch; +} + +std::vector ParseHex(const std::string& str) +{ + return ParseHex(str.c_str()); +} + +std::string EncodeBase64(const unsigned char* pch, size_t len) +{ + static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + std::string strRet = ""; + strRet.reserve((len+2)/3*4); + + int mode=0, left=0; + const unsigned char *pchEnd = pch+len; + + while (pch> 2]; + left = (enc & 3) << 4; + mode = 1; + break; + + case 1: // we have two bits + strRet += pbase64[left | (enc >> 4)]; + left = (enc & 15) << 2; + mode = 2; + break; + + case 2: // we have four bits + strRet += pbase64[left | (enc >> 6)]; + strRet += pbase64[enc & 63]; + mode = 0; + break; + } + } + + if (mode) + { + strRet += pbase64[left]; + strRet += '='; + if (mode == 1) + strRet += '='; + } + + return strRet; +} + +std::string EncodeBase64(const std::string& str) +{ + return EncodeBase64((const unsigned char*)str.c_str(), str.size()); +} + +std::vector DecodeBase64(const char* p, bool* pfInvalid) +{ + static const int decode64_table[256] = + { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, + -1, -1, -1, -1, -1, 0, 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, -1, -1, -1, -1, -1, -1, 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, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }; + + if (pfInvalid) + *pfInvalid = false; + + std::vector vchRet; + vchRet.reserve(strlen(p)*3/4); + + int mode = 0; + int left = 0; + + while (1) + { + int dec = decode64_table[(unsigned char)*p]; + if (dec == -1) break; + p++; + switch (mode) + { + case 0: // we have no bits and get 6 + left = dec; + mode = 1; + break; + + case 1: // we have 6 bits and keep 4 + vchRet.push_back((left<<2) | (dec>>4)); + left = dec & 15; + mode = 2; + break; + + case 2: // we have 4 bits and get 6, we keep 2 + vchRet.push_back((left<<4) | (dec>>2)); + left = dec & 3; + mode = 3; + break; + + case 3: // we have 2 bits and get 6 + vchRet.push_back((left<<6) | dec); + mode = 0; + break; + } + } + + if (pfInvalid) + switch (mode) + { + case 0: // 4n base64 characters processed: ok + break; + + case 1: // 4n+1 base64 character processed: impossible + *pfInvalid = true; + break; + + case 2: // 4n+2 base64 characters processed: require '==' + if (left || p[0] != '=' || p[1] != '=' || decode64_table[(unsigned char)p[2]] != -1) + *pfInvalid = true; + break; + + case 3: // 4n+3 base64 characters processed: require '=' + if (left || p[0] != '=' || decode64_table[(unsigned char)p[1]] != -1) + *pfInvalid = true; + break; + } + + return vchRet; +} + +std::string DecodeBase64(const std::string& str) +{ + std::vector vchRet = DecodeBase64(str.c_str()); + return std::string((const char*)vchRet.data(), vchRet.size()); +} + diff --git a/libraries/fc/vendor/rlpvalue/test/utilstrencodings.h b/libraries/fc/vendor/rlpvalue/test/utilstrencodings.h new file mode 100644 index 00000000..6621ce4f --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/test/utilstrencodings.h @@ -0,0 +1,62 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2017 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +/** + * Utilities for converting data from/to strings. + */ +#ifndef JUP_UTILSTRENCODINGS_H +#define JUP_UTILSTRENCODINGS_H + +#include +#include +#include + +#define BEGIN(a) ((char*)&(a)) +#define END(a) ((char*)&((&(a))[1])) +#define UBEGIN(a) ((unsigned char*)&(a)) +#define UEND(a) ((unsigned char*)&((&(a))[1])) +#define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0])) + +std::vector ParseHex(const char* psz); +std::vector ParseHex(const std::string& str); +signed char HexDigit(char c); +/* Returns true if each character in str is a hex character, and has an even + * number of hex digits.*/ +bool IsHex(const std::string& str); +/** +* Return true if the string is a hex number, optionally prefixed with "0x" +*/ +bool IsHexNumber(const std::string& str); +std::vector DecodeBase64(const char* p, bool* pfInvalid = nullptr); +std::string DecodeBase64(const std::string& str); +std::string EncodeBase64(const unsigned char* pch, size_t len); +std::string EncodeBase64(const std::string& str); + +template +std::string HexStr(const T itbegin, const T itend, bool fSpaces=false) +{ + std::string rv; + static const char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + rv.reserve((itend-itbegin)*3); + for(T it = itbegin; it < itend; ++it) + { + unsigned char val = (unsigned char)(*it); + if(fSpaces && it != itbegin) + rv.push_back(' '); + rv.push_back(hexmap[val>>4]); + rv.push_back(hexmap[val&15]); + } + + return rv; +} + +template +inline std::string HexStr(const T& vch, bool fSpaces=false) +{ + return HexStr(vch.begin(), vch.end(), fSpaces); +} + +#endif // JUP_UTILSTRENCODINGS_H diff --git a/libraries/fc/vendor/rlpvalue/univalue b/libraries/fc/vendor/rlpvalue/univalue new file mode 160000 index 00000000..d6715ee1 --- /dev/null +++ b/libraries/fc/vendor/rlpvalue/univalue @@ -0,0 +1 @@ +Subproject commit d6715ee16ed57bfbfc64e023dcb05151b6654aa4 diff --git a/libraries/net/node.cpp b/libraries/net/node.cpp index 0a27b22d..72a37767 100644 --- a/libraries/net/node.cpp +++ b/libraries/net/node.cpp @@ -3100,7 +3100,6 @@ namespace graphene { namespace net { dlog("in send_sync_block_to_node_delegate()"); bool client_accepted_block = false; - bool discontinue_fetching_blocks_from_peer = false; fc::oexception handle_message_exception; @@ -3139,7 +3138,6 @@ namespace graphene { namespace net { ("id", block_message_to_send.block_id) ("e", (fc::exception)e)); handle_message_exception = e; - discontinue_fetching_blocks_from_peer = true; } catch (const fc::canceled_exception&) { @@ -3242,35 +3240,14 @@ namespace graphene { namespace net { } else { - // invalid message received - for (const peer_connection_ptr& peer : _active_connections) - { - ASSERT_TASK_NOT_PREEMPTED(); // don't yield while iterating over _active_connections - - if (peer->ids_of_items_being_processed.find(block_message_to_send.block_id) != peer->ids_of_items_being_processed.end()) - { - if (discontinue_fetching_blocks_from_peer) - { - wlog("inhibiting fetching sync blocks from peer ${endpoint} because it is on a fork that's too old", - ("endpoint", peer->get_remote_endpoint())); - peer->inhibit_fetching_sync_blocks = true; - } - else - peers_to_disconnect[peer] = std::make_pair(std::string("You offered us a block that we reject as invalid"), fc::oexception(handle_message_exception)); - } - } + // Invalid message received + for (const peer_connection_ptr& peer : _active_connections) + { + wlog("Invalid message received from peer ${endpoint}, ignoring", + ("endpoint", peer->get_remote_endpoint())); + } } - for (auto& peer_to_disconnect : peers_to_disconnect) - { - const peer_connection_ptr& peer = peer_to_disconnect.first; - std::string reason_string; - fc::oexception reason_exception; - std::tie(reason_string, reason_exception) = peer_to_disconnect.second; - wlog("disconnecting client ${endpoint} because it offered us the rejected block", - ("endpoint", peer->get_remote_endpoint())); - disconnect_from_peer(peer.get(), reason_string, true, reason_exception); - } for (const peer_connection_ptr& peer : peers_with_newly_empty_item_lists) fetch_next_batch_of_item_ids_from_peer(peer.get()); diff --git a/libraries/plugins/apis/contract_api/CMakeLists.txt b/libraries/plugins/apis/contract_api/CMakeLists.txt index 7dea6497..26c97202 100644 --- a/libraries/plugins/apis/contract_api/CMakeLists.txt +++ b/libraries/plugins/apis/contract_api/CMakeLists.txt @@ -1,10 +1,17 @@ -file( GLOB HEADERS "include/xgt/plugins/contract_api/*.hpp" ) -set( SOURCES contract_api.cpp contract_api_plugin.cpp ) +file( GLOB HEADERS "include/xgt/plugins/contract_api/*.hpp" "include/keccak256.h" ) +set( SOURCES contract_api.cpp contract_api_plugin.cpp keccak256.c ) add_library( contract_api_plugin ${SOURCES} ${HEADERS} ) -target_link_libraries( contract_api_plugin chain_plugin json_rpc_plugin ) -target_include_directories( contract_api_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) +target_link_libraries( contract_api_plugin + chain_plugin + json_rpc_plugin + xgtvm + ) +target_include_directories( contract_api_plugin + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" + "${CMAKE_CURRENT_SOURCE_DIR}/../../../vendor/xgtvm/libraries" + ) if( CLANG_TIDY_EXE ) set_target_properties( diff --git a/libraries/plugins/apis/contract_api/contract_api.cpp b/libraries/plugins/apis/contract_api/contract_api.cpp index e2186eb5..9b17eb3b 100644 --- a/libraries/plugins/apis/contract_api/contract_api.cpp +++ b/libraries/plugins/apis/contract_api/contract_api.cpp @@ -7,6 +7,10 @@ #include #include +#include "keccak256.h" + +#include + namespace xgt { namespace plugins { namespace contract { namespace detail { @@ -26,8 +30,27 @@ class contract_api_impl DEFINE_API_IMPL( contract_api_impl, get_contract ) { + ilog( "contract_api_impl::get_contract ${c}", ("c",args.contract_hash) ); + + //// TODO: Temporary + //machine::message msg = {}; + //ilog( "machine::message msg.flags ${f}", ("f",msg.flags) ); + + //// TODO: Temporary + //std::string message = "testing"; + //unsigned char output[32]; + //SHA3_CTX ctx; + //keccak_init(&ctx); + //keccak_update(&ctx, (unsigned char*)message.c_str(), message.size()); + //keccak_final(&ctx, output); + + fc::ripemd160 contract_hash(args.contract_hash); + auto& contract = _db.get_contract(contract_hash); get_contract_return result; - result.example = true; + result.contract.id = contract.id; + result.contract.owner = contract.owner; + result.contract.contract_hash = contract.contract_hash; + result.contract.code = contract.code; return result; } @@ -35,15 +58,37 @@ DEFINE_API_IMPL( contract_api_impl, list_owner_contracts ) { list_owner_contracts_return result; - const auto& idx = _db.get_index< chain::contract_index, chain::by_owner >(); + const auto& idx = _db.get_index< chain::contract_index, chain::by_owner_and_contract_hash >(); auto itr = idx.lower_bound( args.owner ); auto end = idx.end(); wlog("!!!!!! LIST_OWNER_CONTRACTS"); while( itr != end ) { - if (itr->owner != args.owner) break; - wlog("!!!!!! LIST_OWNER_CONTRACTS ${w}", ("w",itr->owner)); - result.contracts.push_back(*itr); + auto& c = *itr; + if (c.owner != args.owner) break; + wlog("!!!!!! LIST_OWNER_CONTRACTS ${w}", ("w",c.owner)); + + const std::string& wallet_name_ref = std::string(c.wallet); + + std::string prefix( XGT_ADDRESS_PREFIX ); + + const size_t prefix_len = prefix.size(); + auto b58 = wallet_name_ref.substr( prefix_len ); + auto r160 = fc::ripemd160::hash(b58); + + std::stringstream ss; + ss << std::hex << r160.str(); + std::string en_address; + ss >> en_address; + + api_contract_object ac; + ac.id = c.id; + ac.owner = c.owner; + ac.contract_hash = c.contract_hash; + ac.wallet = c.wallet; + ac.code = c.code; + ac.en_address = en_address; + result.contracts.push_back(ac); ++itr; } diff --git a/libraries/plugins/apis/contract_api/include/keccak256.h b/libraries/plugins/apis/contract_api/include/keccak256.h new file mode 100644 index 00000000..c09b5e02 --- /dev/null +++ b/libraries/plugins/apis/contract_api/include/keccak256.h @@ -0,0 +1,54 @@ +/* sha3 - an implementation of Secure Hash Algorithm 3 (Keccak). + * based on the + * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011 + * by Guido Bertoni, Joan Daemen, Michaƫl Peeters and Gilles Van Assche + * + * Copyright: 2013 Aleksey Kravchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so. + * + * This program 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. Use this program at your own risk! + */ + +#ifndef __KECCAK256_H_ +#define __KECCAK256_H_ + +#include + +#define sha3_max_permutation_size 25 +#define sha3_max_rate_in_qwords 24 + +typedef struct SHA3_CTX { + /* 1600 bits algorithm hashing state */ + uint64_t hash[sha3_max_permutation_size]; + /* 1536-bit buffer for leftovers */ + uint64_t message[sha3_max_rate_in_qwords]; + /* count of bytes in the message[] buffer */ + uint16_t rest; + /* size of a message block processed at once */ + //unsigned block_size; +} SHA3_CTX; + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +void keccak_init(SHA3_CTX *ctx); +void keccak_update(SHA3_CTX *ctx, const unsigned char *msg, uint16_t size); +void keccak_final(SHA3_CTX *ctx, unsigned char* result); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __KECCAK256_H_ */ diff --git a/libraries/plugins/apis/contract_api/include/xgt/plugins/contract_api/contract_api.hpp b/libraries/plugins/apis/contract_api/include/xgt/plugins/contract_api/contract_api.hpp index f626fe21..596bc631 100644 --- a/libraries/plugins/apis/contract_api/include/xgt/plugins/contract_api/contract_api.hpp +++ b/libraries/plugins/apis/contract_api/include/xgt/plugins/contract_api/contract_api.hpp @@ -4,6 +4,7 @@ #include +#include #include #include @@ -12,15 +13,26 @@ namespace xgt { namespace plugins { namespace contract { namespace detail { class contract_api_impl; } +struct api_contract_object +{ + chain::contract_id_type id; + chain::wallet_name_type owner; + chain::wallet_name_type wallet; + chain::contract_hash_type contract_hash; + std::string en_address; + vector code; +}; + + struct get_contract_args { - bool example = true; + chain::contract_hash_type contract_hash; }; struct get_contract_return { - bool example = true; + api_contract_object contract; }; @@ -32,7 +44,7 @@ struct list_owner_contracts_args struct list_owner_contracts_return { - std::vector< chain::contract_object > contracts; + std::vector< api_contract_object > contracts; }; @@ -51,7 +63,15 @@ class contract_api } } } // xgt::plugins::contract -FC_REFLECT( xgt::plugins::contract::get_contract_args, (example) ) -FC_REFLECT( xgt::plugins::contract::get_contract_return, (example) ) +FC_REFLECT( xgt::plugins::contract::api_contract_object, + (id) + (owner) + (wallet) + (contract_hash) + (code) + (en_address) ) + +FC_REFLECT( xgt::plugins::contract::get_contract_args, (contract_hash) ) +FC_REFLECT( xgt::plugins::contract::get_contract_return, (contract) ) FC_REFLECT( xgt::plugins::contract::list_owner_contracts_args, (owner) ) FC_REFLECT( xgt::plugins::contract::list_owner_contracts_return, (contracts) ) diff --git a/libraries/plugins/apis/contract_api/keccak256.c b/libraries/plugins/apis/contract_api/keccak256.c new file mode 100644 index 00000000..f4e1f1de --- /dev/null +++ b/libraries/plugins/apis/contract_api/keccak256.c @@ -0,0 +1,245 @@ +/* sha3 - an implementation of Secure Hash Algorithm 3 (Keccak). + * based on the + * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011 + * by Guido Bertoni, Joan Daemen, Michaƫl Peeters and Gilles Van Assche + * + * Copyright: 2013 Aleksey Kravchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so. + * + * This program 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. Use this program at your own risk! + */ + +#include "keccak256.h" + +//#include + +#include +#include + +#define BLOCK_SIZE ((1600 - 256 * 2) / 8) + +#define I64(x) x##LL +#define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n)))) +#define le2me_64(x) (x) +#define IS_ALIGNED_64(p) (0 == (7 & ((const char*)(p) - (const char*)0))) +#define me64_to_le_str(to, from, length) memcpy((to), (from), (length)) + +/* constants */ + +//const uint8_t round_constant_info[] PROGMEM = { +//const uint8_t constants[] PROGMEM = { +const uint8_t constants[] = { + + 1, 26, 94, 112, 31, 33, 121, 85, 14, 12, 53, 38, 63, 79, 93, 83, 82, 72, 22, 102, 121, 88, 33, 116, +//}; + +//const uint8_t pi_transform[] PROGMEM = { + 1, 6, 9, 22, 14, 20, 2, 12, 13, 19, 23, 15, 4, 24, 21, 8, 16, 5, 3, 18, 17, 11, 7, 10, +//}; + +//const uint8_t rhoTransforms[] PROGMEM = { + 1, 62, 28, 27, 36, 44, 6, 55, 20, 3, 10, 43, 25, 39, 41, 45, 15, 21, 8, 18, 2, 61, 56, 14, +}; + +#define TYPE_ROUND_INFO 0 +#define TYPE_PI_TRANSFORM 24 +#define TYPE_RHO_TRANSFORM 48 + +uint8_t getConstant(uint8_t type, uint8_t index) { + return constants[type + index]; + //return pgm_read_byte(&constants[type + index]); +} + +static uint64_t get_round_constant(uint8_t round) { + uint64_t result = 0; + + //uint8_t roundInfo = pgm_read_byte(&round_constant_info[round]); + uint8_t roundInfo = getConstant(TYPE_ROUND_INFO, round); + if (roundInfo & (1 << 6)) { result |= ((uint64_t)1 << 63); } + if (roundInfo & (1 << 5)) { result |= ((uint64_t)1 << 31); } + if (roundInfo & (1 << 4)) { result |= ((uint64_t)1 << 15); } + if (roundInfo & (1 << 3)) { result |= ((uint64_t)1 << 7); } + if (roundInfo & (1 << 2)) { result |= ((uint64_t)1 << 3); } + if (roundInfo & (1 << 1)) { result |= ((uint64_t)1 << 1); } + if (roundInfo & (1 << 0)) { result |= ((uint64_t)1 << 0); } + + return result; +} + + +/* Initializing a sha3 context for given number of output bits */ +void keccak_init(SHA3_CTX *ctx) { + /* NB: The Keccak capacity parameter = bits * 2 */ + + memset(ctx, 0, sizeof(SHA3_CTX)); +} + +/* Keccak theta() transformation */ +static void keccak_theta(uint64_t *A) { + uint64_t C[5], D[5]; + + for (uint8_t i = 0; i < 5; i++) { + C[i] = A[i]; + for (uint8_t j = 5; j < 25; j += 5) { C[i] ^= A[i + j]; } + } + + for (uint8_t i = 0; i < 5; i++) { + D[i] = ROTL64(C[(i + 1) % 5], 1) ^ C[(i + 4) % 5]; + } + + for (uint8_t i = 0; i < 5; i++) { + //for (uint8_t j = 0; j < 25; j += 5) { + for (uint8_t j = 0; j < 25; j += 5) { A[i + j] ^= D[i]; } + } +} + + +/* Keccak pi() transformation */ +static void keccak_pi(uint64_t *A) { + uint64_t A1 = A[1]; + //for (uint8_t i = 1; i < sizeof(pi_transform); i++) { + for (uint8_t i = 1; i < 24; i++) { + //A[pgm_read_byte(&pi_transform[i - 1])] = A[pgm_read_byte(&pi_transform[i])]; + A[getConstant(TYPE_PI_TRANSFORM, i - 1)] = A[getConstant(TYPE_PI_TRANSFORM, i)]; + } + A[10] = A1; + /* note: A[ 0] is left as is */ +} + +/* +ketch uses 30084 bytes (93%) of program storage space. Maximum is 32256 bytes. +Global variables use 743 bytes (36%) of dynamic memory, leaving 1305 bytes for local variables. Maximum is 2048 bytes. + +*/ +/* Keccak chi() transformation */ +static void keccak_chi(uint64_t *A) { + for (uint8_t i = 0; i < 25; i += 5) { + uint64_t A0 = A[0 + i], A1 = A[1 + i]; + A[0 + i] ^= ~A1 & A[2 + i]; + A[1 + i] ^= ~A[2 + i] & A[3 + i]; + A[2 + i] ^= ~A[3 + i] & A[4 + i]; + A[3 + i] ^= ~A[4 + i] & A0; + A[4 + i] ^= ~A0 & A1; + } +} + + +static void sha3_permutation(uint64_t *state) { + //for (uint8_t round = 0; round < sizeof(round_constant_info); round++) { + for (uint8_t round = 0; round < 24; round++) { + keccak_theta(state); + + /* apply Keccak rho() transformation */ + for (uint8_t i = 1; i < 25; i++) { + //state[i] = ROTL64(state[i], pgm_read_byte(&rhoTransforms[i - 1])); + state[i] = ROTL64(state[i], getConstant(TYPE_RHO_TRANSFORM, i - 1)); + } + + keccak_pi(state); + keccak_chi(state); + + /* apply iota(state, round) */ + *state ^= get_round_constant(round); + } +} + +/** + * The core transformation. Process the specified block of data. + * + * @param hash the algorithm state + * @param block the message block to process + * @param block_size the size of the processed block in bytes + */ +static void sha3_process_block(uint64_t hash[25], const uint64_t *block) { + for (uint8_t i = 0; i < 17; i++) { + hash[i] ^= le2me_64(block[i]); + } + + /* make a permutation of the hash */ + sha3_permutation(hash); +} + +//#define SHA3_FINALIZED 0x80000000 +//#define SHA3_FINALIZED 0x8000 + +/** + * Calculate message hash. + * Can be called repeatedly with chunks of the message to be hashed. + * + * @param ctx the algorithm context containing current hashing state + * @param msg message chunk + * @param size length of the message chunk + */ +void keccak_update(SHA3_CTX *ctx, const unsigned char *msg, uint16_t size) +{ + uint16_t idx = (uint16_t)ctx->rest; + + //if (ctx->rest & SHA3_FINALIZED) return; /* too late for additional input */ + ctx->rest = (unsigned)((ctx->rest + size) % BLOCK_SIZE); + + /* fill partial block */ + if (idx) { + uint16_t left = BLOCK_SIZE - idx; + memcpy((char*)ctx->message + idx, msg, (size < left ? size : left)); + if (size < left) return; + + /* process partial block */ + sha3_process_block(ctx->hash, ctx->message); + msg += left; + size -= left; + } + + while (size >= BLOCK_SIZE) { + uint64_t* aligned_message_block; + if (IS_ALIGNED_64(msg)) { + // the most common case is processing of an already aligned message without copying it + aligned_message_block = (uint64_t*)(void*)msg; + } else { + memcpy(ctx->message, msg, BLOCK_SIZE); + aligned_message_block = ctx->message; + } + + sha3_process_block(ctx->hash, aligned_message_block); + msg += BLOCK_SIZE; + size -= BLOCK_SIZE; + } + + if (size) { + memcpy(ctx->message, msg, size); /* save leftovers */ + } +} + +/** +* Store calculated hash into the given array. +* +* @param ctx the algorithm context containing current hashing state +* @param result calculated hash in binary form +*/ +void keccak_final(SHA3_CTX *ctx, unsigned char* result) +{ + uint16_t digest_length = 100 - BLOCK_SIZE / 2; + +// if (!(ctx->rest & SHA3_FINALIZED)) { + /* clear the rest of the data queue */ + memset((char*)ctx->message + ctx->rest, 0, BLOCK_SIZE - ctx->rest); + ((char*)ctx->message)[ctx->rest] |= 0x01; + ((char*)ctx->message)[BLOCK_SIZE - 1] |= 0x80; + + /* process final block */ + sha3_process_block(ctx->hash, ctx->message); +// ctx->rest = SHA3_FINALIZED; /* mark context as finalized */ +// } + + if (result) { + me64_to_le_str(result, ctx->hash, digest_length); + } +} + diff --git a/libraries/plugins/apis/database_api/database_api.cpp b/libraries/plugins/apis/database_api/database_api.cpp index c024d24d..32af673c 100644 --- a/libraries/plugins/apis/database_api/database_api.cpp +++ b/libraries/plugins/apis/database_api/database_api.cpp @@ -139,9 +139,9 @@ DEFINE_API_IMPL( database_api_impl, get_version ) { return get_version_return ( + fc::string( xgt::utilities::git_revision_description ), fc::string( XGT_BLOCKCHAIN_VERSION ), fc::string( xgt::utilities::git_revision_sha ), - fc::string( fc::git_revision_sha ), _db.get_chain_id() ); } diff --git a/libraries/plugins/apis/database_api/include/xgt/plugins/database_api/database_api_args.hpp b/libraries/plugins/apis/database_api/include/xgt/plugins/database_api/database_api_args.hpp index 82134223..36c68542 100644 --- a/libraries/plugins/apis/database_api/include/xgt/plugins/database_api/database_api_args.hpp +++ b/libraries/plugins/apis/database_api/include/xgt/plugins/database_api/database_api_args.hpp @@ -86,12 +86,12 @@ typedef void_type get_version_args; struct get_version_return { get_version_return() {} - get_version_return( fc::string bc_v, fc::string s_v, fc::string fc_v, chain_id_type c_id ) - :blockchain_version( bc_v ), xgt_revision( s_v ), fc_revision( fc_v ), chain_id( c_id ) {} + get_version_return( fc::string xgt_v, fc::string bc_v, fc::string s_v, chain_id_type c_id ) + :xgt_version(xgt_v), blockchain_version( bc_v ), xgt_revision( s_v ), chain_id( c_id ) {} + fc::string xgt_version; fc::string blockchain_version; fc::string xgt_revision; - fc::string fc_revision; chain_id_type chain_id; }; @@ -351,7 +351,7 @@ typedef find_xtt_token_balances_return list_xtt_token_balances_return; } } } // xgt::database_api FC_REFLECT( xgt::plugins::database_api::get_version_return, - (blockchain_version)(xgt_revision)(fc_revision)(chain_id) ) + (xgt_version)(blockchain_version)(xgt_revision)(chain_id) ) FC_REFLECT_ENUM( xgt::plugins::database_api::sort_order_type, (by_name) diff --git a/libraries/plugins/apis/database_api/include/xgt/plugins/database_api/database_api_objects.hpp b/libraries/plugins/apis/database_api/include/xgt/plugins/database_api/database_api_objects.hpp index b7e5beb8..a066e68c 100644 --- a/libraries/plugins/apis/database_api/include/xgt/plugins/database_api/database_api_objects.hpp +++ b/libraries/plugins/apis/database_api/include/xgt/plugins/database_api/database_api_objects.hpp @@ -106,6 +106,7 @@ struct api_wallet_object api_wallet_object( const wallet_object& a, const database& db ) : id( a.id ), name( a.name ), + en_address( a.en_address ), memo_key( a.memo_key ), last_account_update( a.last_account_update ), created( a.created ), @@ -150,6 +151,7 @@ struct api_wallet_object wallet_id_type id; wallet_name_type name; + en_address_type en_address; authority recovery; authority money; authority social; @@ -370,7 +372,7 @@ FC_REFLECT( xgt::plugins::database_api::api_comment_vote_object, ) FC_REFLECT( xgt::plugins::database_api::api_wallet_object, - (id)(name)(recovery)(money)(social)(memo_key)(json_metadata)(social_json_metadata)(last_recovery_update)(last_account_update) + (id)(name)(en_address)(recovery)(money)(social)(memo_key)(json_metadata)(social_json_metadata)(last_recovery_update)(last_account_update) (created)(mined) (recovery_account)(last_account_recovery)(reset_account) (comment_count)(lifetime_vote_count)(post_count)(can_vote)(energybar) diff --git a/libraries/plugins/p2p/include/xgt/plugins/p2p/p2p_default_seeds.hpp b/libraries/plugins/p2p/include/xgt/plugins/p2p/p2p_default_seeds.hpp index d36c5131..9d55ddd9 100644 --- a/libraries/plugins/p2p/include/xgt/plugins/p2p/p2p_default_seeds.hpp +++ b/libraries/plugins/p2p/include/xgt/plugins/p2p/p2p_default_seeds.hpp @@ -9,14 +9,6 @@ namespace xgt{ namespace plugins { namespace p2p { const std::vector< std::string > default_seeds; #else const std::vector< std::string > default_seeds = { - "xgt.rag.pub:2001", - "xgt2.rag.pub:2001", - "68.129.31.2:2001", - "95.216.69.92:2001", - "95.216.71.199:2001", - "98.33.76.100:2001", - "116.202.114.157:2001", - "195.201.167.19:2001" }; #endif diff --git a/libraries/plugins/p2p/p2p_plugin.cpp b/libraries/plugins/p2p/p2p_plugin.cpp index 32094175..3022e54a 100644 --- a/libraries/plugins/p2p/p2p_plugin.cpp +++ b/libraries/plugins/p2p/p2p_plugin.cpp @@ -111,6 +111,7 @@ class p2p_plugin_impl : public graphene::net::node_delegate uint32_t max_connections = 0; bool force_validate = false; bool block_producer = false; + bool from_genesis = false; std::atomic_bool ready_to_mine; std::atomic_bool running; std::atomic_bool activeHandleBlock; @@ -569,6 +570,7 @@ void p2p_plugin::set_program_options( bpo::options_description& cli, bpo::option cli.add_options() ("force-validate", bpo::bool_switch()->default_value(false), "Force validation of all transactions. Deprecated in favor of p2p-force-validate" ) ("p2p-force-validate", bpo::bool_switch()->default_value(false), "Force validation of all transactions." ) + ("from-genesis", bpo::bool_switch()->default_value(false), "Start chain from genesis." ) ; } @@ -576,7 +578,7 @@ void p2p_plugin::plugin_initialize(const boost::program_options::variables_map& { my = std::make_unique< detail::p2p_plugin_impl >( appbase::app().get_plugin< plugins::chain::chain_plugin >() ); - my->ready_to_mine = false; + my->ready_to_mine = true; if( options.count( "p2p-endpoint" ) ) my->endpoint = fc::ip::endpoint::from_string( options.at( "p2p-endpoint" ).as< string >() ); @@ -633,6 +635,9 @@ void p2p_plugin::plugin_initialize(const boost::program_options::variables_map& } my->force_validate = options.at( "p2p-force-validate" ).as< bool >(); + my->from_genesis = options.at( "from-genesis" ).as< bool >(); + + my->ready_to_mine = my->from_genesis; if( !my->force_validate && options.at( "force-validate" ).as< bool >() ) { diff --git a/libraries/protocol/get_config.cpp b/libraries/protocol/get_config.cpp index b5b2db9f..35d2ca38 100644 --- a/libraries/protocol/get_config.cpp +++ b/libraries/protocol/get_config.cpp @@ -153,6 +153,7 @@ fc::variant_object get_config() result["XGT_UPVOTE_LOCKOUT_SECONDS"] = XGT_UPVOTE_LOCKOUT_SECONDS; result["XGT_VOTE_DUST_THRESHOLD"] = XGT_VOTE_DUST_THRESHOLD; result["XGT_VOTING_ENERGY_REGENERATION_SECONDS"] = XGT_VOTING_ENERGY_REGENERATION_SECONDS; + result["XGT_ENERGY_REGENERATION_SECONDS"] = XGT_ENERGY_REGENERATION_SECONDS; result["XGT_VIRTUAL_SCHEDULE_LAP_LENGTH"] = XGT_VIRTUAL_SCHEDULE_LAP_LENGTH; result["XGT_VIRTUAL_SCHEDULE_LAP_LENGTH2"] = XGT_VIRTUAL_SCHEDULE_LAP_LENGTH2; result["XGT_VOTES_PER_PERIOD_XTT_HF"] = XGT_VOTES_PER_PERIOD_XTT_HF; diff --git a/libraries/protocol/include/xgt/protocol/config.hpp b/libraries/protocol/include/xgt/protocol/config.hpp index acf72a00..33aca133 100644 --- a/libraries/protocol/include/xgt/protocol/config.hpp +++ b/libraries/protocol/include/xgt/protocol/config.hpp @@ -12,8 +12,14 @@ #define XGT_BLOCKCHAIN_VERSION ( version(0, 0, 0) ) #define XGT_ADDRESS_PREFIX "XGT" -#define XGT_CHAIN_ID fc::sha256::hash("xgt") /// All zeroes -#define XGT_WALLET_NAME_LENGTH 40 /// NOTE: If you change this, change XGT_INIT_MINER_NAME also. + +#ifdef IS_TEST_NET +#define XGT_CHAIN_ID fc::sha256::hash("testnet") +#else +#define XGT_CHAIN_ID fc::sha256::hash("xgt") +#endif + +#define XGT_WALLET_NAME_LENGTH 40 /// NOTE: If you change this, change XGT_INIT_MINER_NAME also. #ifdef IS_TEST_NET #define XGT_NETWORK_TYPE "testnet" @@ -22,8 +28,9 @@ #endif #ifdef IS_TEST_NET -#define XGT_INIT_PRIVATE_KEY (fc::ecc::private_key::regenerate(fc::sha256::hash(std::string("init_key")))) -#define XGT_INIT_PUBLIC_KEY_STR (std::string( xgt::protocol::public_key_type(XGT_INIT_PRIVATE_KEY.get_public_key()) )) +// #define XGT_INIT_PRIVATE_KEY (fc::ecc::private_key::regenerate(fc::sha256::hash(std::string("init_key")))) +// #define XGT_INIT_PUBLIC_KEY_STR (std::string( xgt::protocol::public_key_type(XGT_INIT_PRIVATE_KEY.get_public_key()) )) +#define XGT_INIT_PUBLIC_KEY_STR "XGT5zYjtBDvJCQmmUSUwdh7kW2xLVhZB2moLERGHR3GW4vPpfLPrt" #else #define XGT_INIT_PUBLIC_KEY_STR "XGT7dDoJbrmueAw431pPbjLDoRhqFCC5Xs5o6f1cZLepWEpkcy3Tc" #endif @@ -99,6 +106,7 @@ #define XGT_MAX_TIME_UNTIL_EXPIRATION (60*60) // seconds, aka: 1 hour #define XGT_MAX_MEMO_SIZE 2048 #define XGT_VOTING_ENERGY_REGENERATION_SECONDS (1*60*60*24) // 1 day +#define XGT_ENERGY_REGENERATION_SECONDS (1*60*60*24) // 1 day #define XGT_MAX_VOTE_CHANGES 5 #define XGT_REVERSE_AUCTION_WINDOW_SECONDS (60*5) /// 5 minutes #define XGT_MIN_VOTE_INTERVAL_SEC 3 diff --git a/libraries/protocol/include/xgt/protocol/schema_types/wallet_name_type.hpp b/libraries/protocol/include/xgt/protocol/schema_types/wallet_name_type.hpp index d0d80dce..c2cd1f37 100644 --- a/libraries/protocol/include/xgt/protocol/schema_types/wallet_name_type.hpp +++ b/libraries/protocol/include/xgt/protocol/schema_types/wallet_name_type.hpp @@ -6,37 +6,55 @@ #include -namespace xgt { namespace schema { namespace detail { +namespace xgt { + namespace schema { + namespace detail { -////////////////////////////////////////////// -// wallet_name_type // -////////////////////////////////////////////// + ////////////////////////////////////////////// + // wallet_name_type // + ////////////////////////////////////////////// -struct schema_wallet_name_type_impl - : public abstract_schema -{ - XGT_SCHEMA_CLASS_BODY( schema_wallet_name_type_impl ) -}; + struct schema_wallet_name_type_impl : public abstract_schema + { + XGT_SCHEMA_CLASS_BODY( schema_wallet_name_type_impl ) + }; -} + } -template<> -struct schema_reflect< xgt::protocol::wallet_name_type > -{ - typedef detail::schema_wallet_name_type_impl schema_impl_type; -}; + template<> struct schema_reflect< xgt::protocol::wallet_name_type > + { + typedef detail::schema_wallet_name_type_impl schema_impl_type; + }; -} } + } +} namespace fc { -template<> -struct get_typename< xgt::protocol::wallet_name_type > -{ - static const char* name() + template<> struct get_typename< xgt::protocol::wallet_name_type > { - return "xgt::protocol::wallet_name_type"; - } -}; + static const char* name() + { + return "xgt::protocol::wallet_name_type"; + } + }; + +} +namespace xgt { + namespace schema { + namespace detail { + + ////////////////////////////////////////////// + // en_address_type // + ////////////////////////////////////////////// + + struct schema_en_address_type_impl : public abstract_schema + { + XGT_SCHEMA_CLASS_BODY( schema_en_address_type_impl ) + }; + + } + + } } diff --git a/libraries/protocol/include/xgt/protocol/types.hpp b/libraries/protocol/include/xgt/protocol/types.hpp index c40b1b01..b1b256e1 100644 --- a/libraries/protocol/include/xgt/protocol/types.hpp +++ b/libraries/protocol/include/xgt/protocol/types.hpp @@ -73,6 +73,7 @@ namespace xgt { typedef fc::sha256 chain_id_type; typedef fixed_string<8> xtt_ticker_type; typedef fixed_string<256> wallet_name_type; + typedef fixed_string<256> en_address_type; typedef fc::ripemd160 block_id_type; typedef fc::ripemd160 checksum_type; typedef fc::ripemd160 transaction_id_type; diff --git a/libraries/protocol/include/xgt/protocol/xgt_operations.hpp b/libraries/protocol/include/xgt/protocol/xgt_operations.hpp index dd8ddf90..66ec9aba 100644 --- a/libraries/protocol/include/xgt/protocol/xgt_operations.hpp +++ b/libraries/protocol/include/xgt/protocol/xgt_operations.hpp @@ -16,6 +16,7 @@ namespace xgt { namespace protocol { asset fee; wallet_name_type creator; wallet_name_type new_wallet_name; + string en_address; authority recovery; authority money; authority social; @@ -591,6 +592,7 @@ namespace xgt { namespace protocol { struct contract_create_operation : public base_operation { wallet_name_type owner; + wallet_name_type wallet; vector code; void validate()const; @@ -605,7 +607,8 @@ namespace xgt { namespace protocol { { wallet_name_type caller; contract_hash_type contract_hash; - vector< vector > args; + uint64_t value; + vector args; void validate()const; uint64_t energy_cost()const { return 0; } @@ -662,5 +665,5 @@ FC_REFLECT( xgt::protocol::request_wallet_recovery_operation, (recovery_account) FC_REFLECT( xgt::protocol::recover_wallet_operation, (account_to_recover)(new_recovery_authority)(recent_recovery_authority)(extensions) ); FC_REFLECT( xgt::protocol::change_recovery_wallet_operation, (account_to_recover)(new_recovery_account)(extensions) ); -FC_REFLECT( xgt::protocol::contract_create_operation, (owner)(code) ); -FC_REFLECT( xgt::protocol::contract_invoke_operation, (caller)(contract_hash)(args) ); +FC_REFLECT( xgt::protocol::contract_create_operation, (owner)(wallet)(code) ); +FC_REFLECT( xgt::protocol::contract_invoke_operation, (caller)(contract_hash)(value)(args) ); diff --git a/libraries/vendor/xgtvm/.gitignore b/libraries/vendor/xgtvm/.gitignore new file mode 100644 index 00000000..4d1fa76a --- /dev/null +++ b/libraries/vendor/xgtvm/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +build/ +*.un~ diff --git a/libraries/vendor/xgtvm/CMakeLists.txt b/libraries/vendor/xgtvm/CMakeLists.txt new file mode 100644 index 00000000..49eb0840 --- /dev/null +++ b/libraries/vendor/xgtvm/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 2.8.9) +project(Xgtvm) + +find_package( Boost REQUIRED ) +include_directories( ${Boost_INCLUDE_DIR} ) + +# Library +add_library(xgtvm programs/xgtvm.cpp libraries/machine.cpp libraries/machine.hpp) +target_link_libraries( xgtvm LINK_PUBLIC ${Boost_LIBRARIES} ) +target_include_directories(xgtvm PRIVATE libraries) +# Binary +add_executable(xgtvmd programs/xgtvm.cpp libraries/machine.cpp libraries/machine.hpp) +target_link_libraries( xgtvmd LINK_PUBLIC ${Boost_LIBRARIES} ) +target_include_directories(xgtvmd PRIVATE libraries) +# Tests +add_executable(xgtvm_tests programs/xgtvm_tests.cpp libraries/machine.cpp libraries/machine.hpp) +target_link_libraries( xgtvm_tests LINK_PUBLIC ${Boost_LIBRARIES} ) +target_include_directories(xgtvm_tests PRIVATE libraries) diff --git a/libraries/vendor/xgtvm/README.md b/libraries/vendor/xgtvm/README.md new file mode 100644 index 00000000..43019e82 --- /dev/null +++ b/libraries/vendor/xgtvm/README.md @@ -0,0 +1,43 @@ +## TODO + +* Disable-able debug logging +* Variants on stack + +```sh +sudo apt-get install -y build-essential cmake jq libboost-all-dev +``` + +```sh +brew install cmake jq +``` + +```sh +rm -rf build # removes build artifacts +mkdir -p build # create the build directory +(cd build && cmake ..) # configure the project +(cd build && cmake --build .) # build the project +(cd build && ./xgtvm -e'60 01 00' # runs the project +``` + +To manage the project more easily, if you have Ruby installed: + +```sh +rake -T # list tasks that can be run +rake clean # removes build artifacts +rake configure # configures the project +rake make # builds the project +rake test # runs the project +rake # configures and makes the project +``` + +Example finished machine data: + +```json +{ + "returnValue": "", + "finalState": { + "pc": 5, + "stack": ["8"] + } +} +``` diff --git a/libraries/vendor/xgtvm/Rakefile b/libraries/vendor/xgtvm/Rakefile new file mode 100644 index 00000000..ebe86323 --- /dev/null +++ b/libraries/vendor/xgtvm/Rakefile @@ -0,0 +1,54 @@ +require 'json' + +def which?(cmd_name) + return false + %x([ -x "$(command -v #{cmd_name})" ] && echo yes).length > 0 +end + +def xgtvm_eval(string) + # cmd = %(cd build && ./xgtvmd -e'#{string}') + cmd = %(cd build && echo '#{string}' | ./xgtvmd) + $stderr.puts(cmd) + result = %x(#{cmd}) + JSON.load(result) +end + +desc 'removes build artifacts' +task :clean do + sh %(rm -rf build) +end + +desc 'configures the project' +task :configure do + sh %(mkdir -p build) + sh %(cd build && cmake ..) +end + +desc 'builds the project' +task :make do + sh %(mkdir -p build) + sh %(cd build && cmake --build .) +end + +desc 'runs the project' +task :test do + sh %(cd build && ./xgtvm_tests) + + # result = xgtvm_eval('60 03 60 08 01 00') + result = xgtvm_eval('42 00') + p result + # stack = result.fetch('finalState').fetch('stack') + # raise 'fail' unless stack == ['11'] + + # result = xgtvm_eval('60 00 60 01 5B 60 04 57 00') + # p result + # stack = result.fetch('finalState').fetch('stack') + # raise 'fail' unless stack == [] + + # result = xgtvm_eval('42 00') + # p result + # stack = result.fetch('finalState').fetch('stack') + # raise 'fail' unless stack == [] +end + +task :default => [:configure, :make, :test] diff --git a/libraries/vendor/xgtvm/libraries/machine.cpp b/libraries/vendor/xgtvm/libraries/machine.cpp new file mode 100644 index 00000000..5a45c224 --- /dev/null +++ b/libraries/vendor/xgtvm/libraries/machine.cpp @@ -0,0 +1,2919 @@ +#include "machine.hpp" + +namespace machine +{ + + // void emit_log(const evmc::address& _addr, const uint8_t* _data, size_t _dataSize, + // const evmc::bytes32 _topics[], size_t _numTopics); + + boost::multiprecision::uint256_t alias_to_uint256_t(boost::multiprecision::int256_t i) + { + return (boost::multiprecision::uint256_t)i; + } + + boost::multiprecision::int256_t alias_to_int256_t(boost::multiprecision::uint256_t u) + { + return (boost::multiprecision::int256_t)u; + } + + uint8_t get_byte(boost::multiprecision::uint256_t x, int n) + { + std::vector bytes; + boost::multiprecision::export_bits(x, std::back_inserter(bytes), 8); + return bytes[n]; + } + + uint16_t get_bytes(boost::multiprecision::uint256_t x, int n) + { + std::vector bytes; + boost::multiprecision::export_bits(x, std::back_inserter(bytes), 8); + if (x > 255) { + return ((uint16_t)bytes[n] << 8) | bytes[n + 1]; + } + return bytes[n]; + } + + size_t uint256_t_to_size_t(boost::multiprecision::uint256_t& x) + { + return x.convert_to(); + } + + typed_big_word to_typed_big_word(int64_t a, bool is_sparse = false) + { + return typed_big_word(a, is_sparse); + } + + typed_big_word to_typed_big_word(size_t a, bool is_sparse = false) + { + return typed_big_word(a, is_sparse); + } + + typed_big_word to_typed_big_word(typed_word a, bool is_sparse = false) + { + return typed_big_word(a.value, is_sparse); + } + + typed_big_word to_typed_big_word(typed_word a, typed_word b, bool is_sparse = false) + { + typed_big_word va = (to_typed_big_word(a).value << 8) | to_typed_big_word(b).value; + va.is_sparse = is_sparse; + return va; + } + + typed_big_word to_typed_big_word(typed_word a, typed_word b, typed_word c, typed_word d, bool is_sparse = false) + { + typed_big_word va = (to_typed_big_word(a).value << 8) | to_typed_big_word(b).value; + typed_big_word vb = (va.value << 8) | c.value; + typed_big_word vc = (vb.value << 8) | d.value; + vc.is_sparse = is_sparse; + return vc; + } + + typed_big_word to_typed_big_word(typed_word a, typed_word b, typed_word c, typed_word d, typed_word e, typed_word f, typed_word g, typed_word h, bool is_sparse = false) + { + typed_big_word va = (to_typed_big_word(a).value << 8) | to_typed_big_word(b).value; + typed_big_word vb = (va.value << 8) | c.value; + typed_big_word vc = (vb.value << 8) | d.value; + typed_big_word vd = (vc.value << 8) | e.value; + typed_big_word ve = (vd.value << 8) | f.value; + typed_big_word vf = (ve.value << 8) | g.value; + typed_big_word vg = (vf.value << 8) | h.value; + vg.is_sparse = is_sparse; + return vg; + } + + typed_big_word to_typed_big_word(typed_word a, typed_word b, typed_word c, typed_word d, typed_word e, typed_word f, typed_word g, + typed_word h, typed_word i, typed_word j, typed_word k, typed_word l, typed_word m, typed_word n, typed_word o, typed_word p, bool is_sparse = false) + { + typed_big_word va = (to_typed_big_word(a).value << 8) | to_typed_big_word(b).value; + typed_big_word vb = (va.value << 8) | c.value; + typed_big_word vc = (vb.value << 8) | d.value; + typed_big_word vd = (vc.value << 8) | e.value; + typed_big_word ve = (vd.value << 8) | f.value; + typed_big_word vf = (ve.value << 8) | g.value; + typed_big_word vg = (vf.value << 8) | h.value; + typed_big_word vh = (vg.value << 8) | i.value; + typed_big_word vi = (vh.value << 8) | j.value; + typed_big_word vj = (vi.value << 8) | k.value; + typed_big_word vk = (vj.value << 8) | l.value; + typed_big_word vl = (vk.value << 8) | m.value; + typed_big_word vm = (vl.value << 8) | n.value; + typed_big_word vn = (vm.value << 8) | o.value; + typed_big_word vo = (vn.value << 8) | p.value; + vo.is_sparse = is_sparse; + return vo; + } + + typed_big_word to_typed_big_word(typed_word a, typed_word b, typed_word c, typed_word d, typed_word e, typed_word f, typed_word g, + typed_word h, typed_word i, typed_word j, typed_word k, typed_word l, typed_word m, typed_word n, typed_word o, typed_word p, + typed_word q, typed_word r, typed_word s, typed_word t, typed_word u, typed_word v, typed_word w, typed_word x, typed_word y, + typed_word z, typed_word aa, typed_word ab, typed_word ac, typed_word ad, typed_word ae, typed_word af, bool is_sparse = false) + { + typed_big_word va = (to_typed_big_word(a).value << 8) | to_typed_big_word(b).value; + typed_big_word vb = (va.value << 8) | c.value; + typed_big_word vc = (vb.value << 8) | d.value; + typed_big_word vd = (vc.value << 8) | e.value; + typed_big_word ve = (vd.value << 8) | f.value; + typed_big_word vf = (ve.value << 8) | g.value; + typed_big_word vg = (vf.value << 8) | h.value; + typed_big_word vh = (vg.value << 8) | i.value; + typed_big_word vi = (vh.value << 8) | j.value; + typed_big_word vj = (vi.value << 8) | k.value; + typed_big_word vk = (vj.value << 8) | l.value; + typed_big_word vl = (vk.value << 8) | m.value; + typed_big_word vm = (vl.value << 8) | n.value; + typed_big_word vn = (vm.value << 8) | o.value; + typed_big_word vo = (vn.value << 8) | p.value; + typed_big_word vp = (vo.value << 8) | q.value; + typed_big_word vq = (vp.value << 8) | r.value; + typed_big_word vr = (vq.value << 8) | s.value; + typed_big_word vs = (vr.value << 8) | t.value; + typed_big_word vt = (vs.value << 8) | u.value; + typed_big_word vu = (vt.value << 8) | v.value; + typed_big_word vv = (vu.value << 8) | w.value; + typed_big_word vw = (vv.value << 8) | x.value; + typed_big_word vx = (vw.value << 8) | y.value; + typed_big_word vy = (vx.value << 8) | z.value; + typed_big_word vz = (vy.value << 8) | aa.value; + typed_big_word vaa = (vz.value << 8) | ab.value; + typed_big_word vab = (vaa.value << 8) | ac.value; + typed_big_word vac = (vab.value << 8) | ad.value; + typed_big_word vad = (vac.value << 8) | ae.value; + typed_big_word vae = (vad.value << 8) | af.value; + vae.is_sparse = is_sparse; + return vae; + } + + std::vector from_typed_big_word(typed_big_word a) + { + std::vector vec; + vec.push_back( typed_word( static_cast(a.value & 0xFF), a.is_sparse ) ); + for (size_t i = 0; i < 31; i++) { + vec.push_back( typed_word( static_cast( (a.value >>= 8) & 0xFF ), a.is_sparse ) ); + } + + return vec; + } + + std::string inspect(std::vector words) + { + std::stringstream ss; + ss << "["; + for (size_t i = 0; i < words.size(); i++) + { + ss << std::to_string(words.at(i).value); + if (i != words.size() - 1) + ss << ", "; + } + ss << "]"; + return ss.str(); + } + + std::string inspect(std::map words) + { + std::stringstream ss; + ss << "["; + std::map::iterator it; + size_t i = 0; + while(true) + { + it = words.find(i); + if (it != words.end()) { + ss << std::to_string(it->second.value); + ss << ", "; + } + else { + ss << std::to_string(it->second.value); + break; + } + i++; + } + ss << "]"; + return ss.str(); + } + + void machine::push_word(typed_big_word v) + { + stack.push_front(v); + } + + typed_big_word machine::pop_word() + { + typed_big_word& stack_object = stack.front(); + stack.pop_front(); + return stack_object; + } + + typed_big_word machine::peek_word() + { + typed_big_word& stack_object = stack.front(); + return stack_object; + } + + void machine::print_stack() + { + for (auto it = stack.cbegin(); it != stack.cend(); ++it) + { + typed_big_word w = *it; + logger << w.value; + if (it + 1 != stack.cend()) + logger << " "; + } + logger << std::endl; + } + + size_t machine::stack_length() + { + return stack.size(); + } + + void machine::step() + { + if (code.size() == 0 || pc > code.size()) + { + logger << "stop" << std::endl; + state = machine_state::stopped; + return; + } + word current_instruction = code[pc]; + opcode op = (opcode)current_instruction; + current_opcode = op; + pc++; + + logger << "step pc " << std::to_string(pc) << " opcode " << std::hex << op << std::dec << std::endl; + + // Allow to skip evaluation by throwing exception. + // TODO: Verify this behavior. + typed_word a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, + y, z, aa, ab, ac, ad, ae, af; + typed_big_word va, vb, vc, vd, ve, vf, vg, vh, vi, vj, vk, vl, vm, vn, vo, vp, vq; + + word jumpdest_instruction; + opcode jumpdest_op; + typed_signed_big_word sa, sb, sc; + size_t offset, dest_offset, length, code_size = 0; + // TODO XXX convert words to typed_words + std::vector vec1; + std::vector contract_args; + std::vector retval; + std::vector ext_contract_code; + std::pair< word, std::vector > contract_call_return; + std::vector::const_iterator first, last; + std::stringstream sstream; + switch (op) + { + case stop_opcode: + logger << "op stop" << std::endl; + state = machine_state::stopped; + break; + case add_opcode: + logger << "op add" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = va + vb; + + push_word(vc); + break; + case mul_opcode: + logger << "op mul" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = va * vb; + push_word(vc); + break; + case sub_opcode: + logger << "op sub" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = va - vb; + push_word(vc); + break; + case div_opcode: + logger << "op div" << std::endl; + va = pop_word(); + vb = pop_word(); + if ( vb == typed_big_word(0) ) + push_word( typed_big_word(0) ); + else + vc = va / vb; + push_word(vc); + break; + case sdiv_opcode: + logger << "op sdiv" << std::endl; + sa = alias_to_int256_t( pop_word().value ); + sb = alias_to_int256_t( pop_word().value ); + sc = sa / sb; + push_word( alias_to_uint256_t(sc.value) ); + break; + case mod_opcode: + logger << "op mod" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = va % vb; + push_word(vc); + break; + case smod_opcode: + logger << "op smod" << std::endl; + sa = alias_to_int256_t( pop_word().value ); + sb = alias_to_int256_t( pop_word().value ); + sc = sa % sb; + push_word( alias_to_uint256_t(sc.value) ); + break; + case addmod_opcode: + logger << "op addmod" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = pop_word(); + vd = va + vb; + ve = vd % vc; + push_word(ve); + break; + case mulmod_opcode: + logger << "op addmod" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = pop_word(); + vd = va * vb; + ve = vd % vc; + push_word(ve); + break; + case exp_opcode: + // TODO Implement using boost::multiprecision::pow + logger << "op exp" << std::endl; + va = pop_word(); // base + vb = pop_word(); // exponent + vc = typed_big_word(1); + for (int i = 0; i < vb.value; i++) { + vc *= va; + } + push_word(vc); + break; + case signextend_opcode: + logger << "op signextend" << std::endl; + sa = alias_to_int256_t( pop_word().value ); // b + sb = alias_to_int256_t( pop_word().value ); // x + + if (sa.value < 31) + { + unsigned testBit = static_cast(sa.value) * 8 + 7; + typed_big_word one(1); + typed_big_word mask = ((one.value << testBit) - 1); + if ( (sb & static_cast( (one.value << testBit) ) ) != typed_signed_big_word(0) ) + sc = sb.value | static_cast(~mask.value); + else + sc = sb.value & static_cast(mask.value); + } + + push_word( alias_to_uint256_t(sc.value) ); + break; + case lt_opcode: + logger << "op lt" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = typed_big_word(va < vb); + push_word(vc); + break; + case gt_opcode: + logger << "op gt" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = typed_big_word(va > vb); + push_word(vc); + break; + case slt_opcode: + logger << "op stl" << std::endl; + sa = alias_to_int256_t( pop_word().value ); + sb = alias_to_int256_t( pop_word().value ); + sc = sa < sb ? typed_signed_big_word(1) : typed_signed_big_word(0); + push_word( alias_to_uint256_t(sc.value) ); + break; + case sgt_opcode: + logger << "op sgt" << std::endl; + sa = alias_to_int256_t( pop_word().value ); + sb = alias_to_int256_t( pop_word().value ); + sc = sa > sb ? typed_signed_big_word(1) : typed_signed_big_word(0); + push_word( alias_to_uint256_t(sc.value) ); + break; + case eq_opcode: + logger << "op eq" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = va == vb ? typed_big_word(1) : typed_big_word(0); + push_word(vc); + break; + case iszero_opcode: + logger << "op iszero" << std::endl; + va = pop_word(); + vb = va == typed_big_word(0) ? typed_big_word(1) : typed_big_word(0); + push_word(vb); + break; + case and_opcode: + logger << "op and" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = va & vb; + push_word(vc); + break; + case or_opcode: + logger << "op or" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = va | vb; + push_word(vc); + break; + case xor_opcode: + logger << "op xor" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = va ^ vb; + push_word(vc); + break; + case not_opcode: + logger << "op not" << std::endl; + va = pop_word(); + vb = ~va; + push_word(vb); + break; + case byte_opcode: + logger << "op byte" << std::endl; + + sa = static_cast( pop_word().value ); // index + sb = static_cast( pop_word().value ); // num + + sc = sa.value < 32 ? (sb.value >> (unsigned)(8 * (31 - sa.value))) & 0xff : 0; + + push_word( alias_to_uint256_t(sc.value) ); + break; + case shl_opcode: + logger << "op shl" << std::endl; + + va = pop_word(); // shift + vb = pop_word(); // value + + vc = vb.value << static_cast(va.value); + + push_word(vc); + break; + case shr_opcode: + logger << "op shr" << std::endl; + va = pop_word(); // shift + vb = pop_word(); // value + + // TODO Implement shift in a loop for va sizes larger than 256 + vc = vb.value >> static_cast(va.value); + push_word(vc); + + break; + case sar_opcode: + logger << "op sar" << std::endl; + sa = alias_to_int256_t( pop_word().value ); // shift + sb = static_cast( pop_word().value ); // value + + sc = sb.value >> static_cast(sa.value); + push_word( alias_to_uint256_t(sc.value) ); + + break; + case sha3_opcode: + logger << "op sha3" << std::endl; + va = pop_word(); // offset + vb = pop_word(); // length + + if ( vb == typed_big_word(0) ) { + push_word( typed_big_word(0) ); + } else { + for (size_t i = static_cast(va.value); i < static_cast(va.value) + static_cast(vb.value); i++) { + std::map::iterator it; + it = memory.find(i); + if (it != memory.end()) { + if ( it->second.is_sparse ) { + for (size_t i = 0; i < 31; i++) { + retval.push_back( word(0) ); + } + } + retval.push_back( word(it->second.value) ); + } + else { + if ( it->second.is_sparse ) { + for (size_t i = 0; i < 32; i++) { + retval.push_back( word(0) ); + } + } else { + retval.push_back( word(0) ); + } + } + } + + vc = adapter.sha3( retval ); + push_word( vc ); // hash + } + + break; + case address_opcode: + logger << "op address" << std::endl; + push_word( typed_big_word(msg.destination) ); + break; + case balance_opcode: + logger << "op balance" << std::endl; + va = pop_word(); + push_word( typed_big_word( adapter.get_balance(va.value) ) ); + break; + case origin_opcode: + logger << "op origin" << std::endl; + push_word( ctx.tx_origin ); + break; + case caller_opcode: + logger << "op caller" << std::endl; + push_word( msg.sender ); + break; + case callvalue_opcode: + logger << "op callvalue" << std::endl; + push_word( typed_big_word(msg.value) ); + break; + case calldataload_opcode: + logger << "op calldataload" << std::endl; + va = pop_word(); + offset = static_cast( va.value ); + + if (offset > msg.input_size) { + logger << "calldataload start index is larger than message input_size" << std::endl; + break; + } + + vb = to_typed_big_word( + msg.input_data[offset + 0], + msg.input_data[offset + 1], + msg.input_data[offset + 2], + msg.input_data[offset + 3], + msg.input_data[offset + 4], + msg.input_data[offset + 5], + msg.input_data[offset + 6], + msg.input_data[offset + 7], + msg.input_data[offset + 8], + msg.input_data[offset + 9], + msg.input_data[offset + 10], + msg.input_data[offset + 11], + msg.input_data[offset + 12], + msg.input_data[offset + 13], + msg.input_data[offset + 14], + msg.input_data[offset + 15], + msg.input_data[offset + 16], + msg.input_data[offset + 17], + msg.input_data[offset + 18], + msg.input_data[offset + 19], + msg.input_data[offset + 20], + msg.input_data[offset + 21], + msg.input_data[offset + 22], + msg.input_data[offset + 23], + msg.input_data[offset + 24], + msg.input_data[offset + 25], + msg.input_data[offset + 26], + msg.input_data[offset + 27], + msg.input_data[offset + 28], + msg.input_data[offset + 29], + msg.input_data[offset + 30], + msg.input_data[offset + 31], + true + ); + + push_word(vb); + break; + case calldatasize_opcode: + logger << "op calldatasize" << std::endl; + push_word( to_typed_big_word(msg.input_size) ); + break; + case calldatacopy_opcode: + logger << "op calldatacopy" << std::endl; + + dest_offset = static_cast( pop_word().value ); + offset = static_cast( pop_word().value ); + length = static_cast( pop_word().value ); + + if ((offset + length) > msg.input_size) { + logger << "calldatacopy end index is larger than message input_size" << std::endl; + break; + } + + for (size_t i = 0; i < length; ++i) { + memory[dest_offset + i] = typed_word(msg.input_data[offset + i], true); + } + + break; + case codesize_opcode: + logger << "op codesize" << std::endl; + push_word( to_typed_big_word( code.size() ) ); + break; + case codecopy_opcode: + logger << "op codecopy" << std::endl; + + dest_offset = static_cast( pop_word().value ); + offset = static_cast( pop_word().value ); + length = static_cast( pop_word().value ); + + for (size_t i = 0; i < length; ++i) { + memory[dest_offset + i] = typed_word(code[offset + i], true); + } + + break; + case energyprice_opcode: + logger << "op energyprice" << std::endl; + push_word( to_typed_big_word( ctx.tx_energyprice ) ); + break; + case extcodesize_opcode: + logger << "op extcodesize" << std::endl; + va = pop_word(); // Address + ext_contract_code = adapter.get_code_at_addr(va.value); + push_word( typed_big_word( sizeof(ext_contract_code) / sizeof(ext_contract_code[0]) ) ); + break; + case extcodecopy_opcode: + logger << "op extcodecopy" << std::endl; + va = pop_word(); // address + ext_contract_code = adapter.get_code_at_addr(va.value); + code_size = sizeof(ext_contract_code) / sizeof(ext_contract_code[0]); + dest_offset = static_cast( pop_word().value ); + offset = static_cast( pop_word().value ); + length = static_cast( pop_word().value ); + + if ((offset + length) > code_size) { + logger << "codecopy end index exceeds external contract code length" << std::endl; + break; + } + + for (size_t i = 0; i < length; ++i) { + memory[dest_offset + i] = typed_word(ext_contract_code[offset + i], true); + } + + break; + case returndatasize_opcode: + logger << "op returndatasize" << std::endl; + push_word( typed_big_word( ext_return_data.size() ) ); + break; + case returndatacopy_opcode: + logger << "op returndatacopy" << std::endl; + dest_offset = static_cast( pop_word().value ); + offset = static_cast( pop_word().value ); + length = static_cast( pop_word().value ); + + if ( (offset + length) > ext_return_data.size() ) { + logger << "returndatacopy end index exceeds return data size" << std::endl; + break; + } + + for (size_t i = 0; i < length; ++i) + memory[dest_offset + i] = ext_return_data[offset + i]; + + break; + case extcodehash_opcode: + logger << "op extcodehash" << std::endl; + va = pop_word(); // addr + push_word( typed_big_word( adapter.get_code_hash(va.value) ) ); + break; + case blockhash_opcode: + logger << "op blockhash" << std::endl; + va = pop_word(); + push_word( adapter.get_block_hash( static_cast(va.value) ) ); + break; + case coinbase_opcode: + logger << "op coinbase" << std::endl; + push_word( typed_big_word(ctx.block_coinbase) ); + break; + case timestamp_opcode: + logger << "op timestamp" << std::endl; + push_word( typed_big_word(ctx.block_timestamp) ); + break; + case number_opcode: + logger << "op number" << std::endl; + push_word( typed_big_word(ctx.block_number) ); + break; + case difficulty_opcode: + logger << "op difficulty" << std::endl; + push_word( typed_big_word(ctx.block_difficulty) ); + break; + case energylimit_opcode: + logger << "op energylimit" << std::endl; + push_word( typed_big_word(ctx.block_energylimit) ); + break; + case selfbalance_opcode: + logger << "op selfbalance" << std::endl; + push_word( adapter.get_balance( msg.destination ) ); + break; + case pop_opcode: + logger << "op pop" << std::endl; + pop_word(); + break; + case mload_opcode: + logger << "op mload" << std::endl; + va = pop_word(); // offset + vb = to_typed_big_word( + memory[static_cast(va.value) + 0], + memory[static_cast(va.value) + 1], + memory[static_cast(va.value) + 2], + memory[static_cast(va.value) + 3], + memory[static_cast(va.value) + 4], + memory[static_cast(va.value) + 5], + memory[static_cast(va.value) + 6], + memory[static_cast(va.value) + 7], + memory[static_cast(va.value) + 8], + memory[static_cast(va.value) + 9], + memory[static_cast(va.value) + 10], + memory[static_cast(va.value) + 11], + memory[static_cast(va.value) + 12], + memory[static_cast(va.value) + 13], + memory[static_cast(va.value) + 14], + memory[static_cast(va.value) + 15], + memory[static_cast(va.value) + 16], + memory[static_cast(va.value) + 17], + memory[static_cast(va.value) + 18], + memory[static_cast(va.value) + 19], + memory[static_cast(va.value) + 20], + memory[static_cast(va.value) + 21], + memory[static_cast(va.value) + 22], + memory[static_cast(va.value) + 23], + memory[static_cast(va.value) + 24], + memory[static_cast(va.value) + 25], + memory[static_cast(va.value) + 26], + memory[static_cast(va.value) + 27], + memory[static_cast(va.value) + 28], + memory[static_cast(va.value) + 29], + memory[static_cast(va.value) + 30], + memory[static_cast(va.value) + 31], + memory[static_cast(va.value)].is_sparse + ); + + push_word(vb); + break; + case mstore_opcode: + logger << "op mstore" << std::endl; + va = pop_word(); // offset + vb = pop_word(); // value + logger << "memory before: " << inspect(memory) << std::endl; + + vec1 = from_typed_big_word(vb); + for (size_t i = 0; i < 32; i++) + memory[static_cast(va.value) + i] = vec1[31 - i]; + + logger << "memory after: " << inspect(memory) << std::endl; + break; + case mstore8_opcode: + logger << "op mstore8" << std::endl; + va = pop_word(); // offset + vb = pop_word(); // value + logger << "memory before: " << inspect(memory) << std::endl; + memory[static_cast(va.value)] = get_byte(vb.value, 0); // TODO verify byte of typed_big_word vb + logger << "memory after: " << inspect(memory) << std::endl; + break; + case sload_opcode: + logger << "op sload" << std::endl; + va = pop_word(); + vb = typed_big_word( adapter.get_storage(va.value) ); + + push_word(vb); + break; + case sstore_opcode: + logger << "op sstore" << std::endl; + va = pop_word(); + vb = pop_word(); + + adapter.set_storage(va.value, vb.value); + break; + case jump_opcode: + logger << "op jump" << std::endl; + va = pop_word(); // destination + + jumpdest_instruction = code[get_bytes( va.value, 0 )]; + jumpdest_op = (opcode)jumpdest_instruction; + if (jumpdest_op == jumpdest_opcode) + pc = get_bytes( va.value, 0 ); + break; + case jumpi_opcode: + logger << "op jumpi" << std::endl; + print_stack(); + va = pop_word(); // destination + vb = pop_word(); // condition + + if (vb != typed_big_word(0)) { + jumpdest_instruction = code[get_bytes( va.value, 0 )]; + jumpdest_op = (opcode)jumpdest_instruction; + if (jumpdest_op == jumpdest_opcode) + pc = get_bytes( va.value, 0 ); + } + break; + case pc_opcode: + logger << "op pc" << std::endl; + va = typed_big_word(pc); + push_word(va); + break; + case msize_opcode: + logger << "op msize" << std::endl; + push_word( to_typed_big_word( memory.size() ) ); + break; + case energy_opcode: + logger << "op energy" << std::endl; + push_word(energy_left); + break; + case jumpdest_opcode: + logger << "op jumpdest" << std::endl; + break; + case push1_opcode: + logger << "op push1" << std::endl; + a = code[pc]; + pc++; + push_word(to_typed_big_word(a)); + break; + case push2_opcode: + logger << "op push2" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + va = to_typed_big_word(a, b); + push_word(va); + break; + case push3_opcode: + logger << "op push3" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + va = to_typed_big_word(0, a, b, c); + push_word(va); + break; + case push4_opcode: + logger << "op push4" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + va = to_typed_big_word(a, b, c, d); + push_word(va); + break; + case push5_opcode: + logger << "op push5" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + va = to_typed_big_word(0, 0, 0, a, b, c, d, e); + push_word(va); + break; + case push6_opcode: + logger << "op push6" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + va = to_typed_big_word(0, 0, a, b, c, d, e, f); + push_word(va); + break; + case push7_opcode: + logger << "op push7" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + va = to_typed_big_word(0, a, b, c, d, e, f, g); + push_word(va); + break; + case push8_opcode: + logger << "op push8" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + va = to_typed_big_word(a, b, c, d, e, f, g, h); + push_word(va); + break; + case push9_opcode: + logger << "op push9" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + va = to_typed_big_word(0, 0, 0, 0, 0, 0, 0, a, b, c, d, e, f, g, h, i); + push_word(va); + break; + case push10_opcode: + logger << "op push10" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + va = to_typed_big_word(0, 0, 0, 0, 0, 0, a, b, c, d, e, f, g, h, i, j); + push_word(va); + break; + case push11_opcode: + logger << "op push11" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + va = to_typed_big_word(0, 0, 0, 0, 0, a, b, c, d, e, f, g, h, i, j, k); + push_word(va); + break; + case push12_opcode: + logger << "op push12" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + l = code[pc]; + pc++; + va = to_typed_big_word(0, 0, 0, 0, a, b, c, d, e, f, g, h, i, j, k, l); + push_word(va); + break; + case push13_opcode: + logger << "op push13" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + l = code[pc]; + pc++; + m = code[pc]; + pc++; + va = to_typed_big_word(0, 0, 0, a, b, c, d, e, f, g, h, i, j, k, l, m); + push_word(va); + break; + case push14_opcode: + logger << "op push14" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + l = code[pc]; + pc++; + m = code[pc]; + pc++; + n = code[pc]; + pc++; + va = to_typed_big_word(0, 0, a, b, c, d, e, f, g, h, i, j, k, l, m, n); + push_word(va); + break; + case push15_opcode: + logger << "op push15" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + l = code[pc]; + pc++; + m = code[pc]; + pc++; + n = code[pc]; + pc++; + o = code[pc]; + pc++; + va = to_typed_big_word(0, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o); + push_word(va); + break; + case push16_opcode: + logger << "op push16" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + l = code[pc]; + pc++; + m = code[pc]; + pc++; + n = code[pc]; + pc++; + o = code[pc]; + pc++; + p = code[pc]; + pc++; + va = to_typed_big_word(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p); + push_word(va); + break; + case push17_opcode: + logger << "op push17" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + l = code[pc]; + pc++; + m = code[pc]; + pc++; + n = code[pc]; + pc++; + o = code[pc]; + pc++; + p = code[pc]; + pc++; + q = code[pc]; + pc++; + va = to_typed_big_word(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d, + e, f, g, h, i, j, k, l, m, n, o, p, q); + push_word(va); + break; + case push18_opcode: + logger << "op push18" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + l = code[pc]; + pc++; + m = code[pc]; + pc++; + n = code[pc]; + pc++; + o = code[pc]; + pc++; + p = code[pc]; + pc++; + q = code[pc]; + pc++; + r = code[pc]; + pc++; + va = to_typed_big_word(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d, e, + f, g, h, i, j, k, l, m, n, o, p, q, r); + push_word(va); + break; + case push19_opcode: + logger << "op push19" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + l = code[pc]; + pc++; + m = code[pc]; + pc++; + n = code[pc]; + pc++; + o = code[pc]; + pc++; + p = code[pc]; + pc++; + q = code[pc]; + pc++; + r = code[pc]; + pc++; + s = code[pc]; + pc++; + va = to_typed_big_word(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d, e, f, + g, h, i, j, k, l, m, n, o, p, q, r, s); + push_word(va); + break; + case push20_opcode: + logger << "op push20" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + l = code[pc]; + pc++; + m = code[pc]; + pc++; + n = code[pc]; + pc++; + o = code[pc]; + pc++; + p = code[pc]; + pc++; + q = code[pc]; + pc++; + r = code[pc]; + pc++; + s = code[pc]; + pc++; + t = code[pc]; + pc++; + va = to_typed_big_word(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d, e, f, g, + h, i, j, k, l, m, n, o, p, q, r, s, t); + push_word(va); + break; + case push21_opcode: + logger << "op push21" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + l = code[pc]; + pc++; + m = code[pc]; + pc++; + n = code[pc]; + pc++; + o = code[pc]; + pc++; + p = code[pc]; + pc++; + q = code[pc]; + pc++; + r = code[pc]; + pc++; + s = code[pc]; + pc++; + t = code[pc]; + pc++; + u = code[pc]; + pc++; + va = to_typed_big_word(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d, e, f, g, h, + i, j, k, l, m, n, o, p, q, r, s, t, u); + push_word(va); + break; + case push22_opcode: + logger << "op push22" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + l = code[pc]; + pc++; + m = code[pc]; + pc++; + n = code[pc]; + pc++; + o = code[pc]; + pc++; + p = code[pc]; + pc++; + q = code[pc]; + pc++; + r = code[pc]; + pc++; + s = code[pc]; + pc++; + t = code[pc]; + pc++; + u = code[pc]; + pc++; + v = code[pc]; + pc++; + va = to_typed_big_word(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d, e, f, g, h, i, + j, k, l, m, n, o, p, q, r, s, t, u, v); + push_word(va); + break; + case push23_opcode: + logger << "op push23" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + l = code[pc]; + pc++; + m = code[pc]; + pc++; + n = code[pc]; + pc++; + o = code[pc]; + pc++; + p = code[pc]; + pc++; + q = code[pc]; + pc++; + r = code[pc]; + pc++; + s = code[pc]; + pc++; + t = code[pc]; + pc++; + u = code[pc]; + pc++; + v = code[pc]; + pc++; + w = code[pc]; + pc++; + va = to_typed_big_word(0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d, e, f, g, h, i, j, + k, l, m, n, o, p, q, r, s, t, u, v, w); + push_word(va); + break; + case push24_opcode: + logger << "op push24" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + l = code[pc]; + pc++; + m = code[pc]; + pc++; + n = code[pc]; + pc++; + o = code[pc]; + pc++; + p = code[pc]; + pc++; + q = code[pc]; + pc++; + r = code[pc]; + pc++; + s = code[pc]; + pc++; + t = code[pc]; + pc++; + u = code[pc]; + pc++; + v = code[pc]; + pc++; + w = code[pc]; + pc++; + x = code[pc]; + pc++; + va = to_typed_big_word(0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d, e, f, g, h, i, j, k, + l, m, n, o, p, q, r, s, t, u, v, w, x); + push_word(va); + break; + case push25_opcode: + logger << "op push25" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + l = code[pc]; + pc++; + m = code[pc]; + pc++; + n = code[pc]; + pc++; + o = code[pc]; + pc++; + p = code[pc]; + pc++; + q = code[pc]; + pc++; + r = code[pc]; + pc++; + s = code[pc]; + pc++; + t = code[pc]; + pc++; + u = code[pc]; + pc++; + v = code[pc]; + pc++; + w = code[pc]; + pc++; + x = code[pc]; + pc++; + y = code[pc]; + pc++; + va = to_typed_big_word(0, 0, 0, 0, 0, 0, 0, a, b, c, d, e, f, g, h, i, j, k, l, + m, n, o, p, q, r, s, t, u, v, w, x, y); + push_word(va); + break; + case push26_opcode: + logger << "op push26" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + l = code[pc]; + pc++; + m = code[pc]; + pc++; + n = code[pc]; + pc++; + o = code[pc]; + pc++; + p = code[pc]; + pc++; + q = code[pc]; + pc++; + r = code[pc]; + pc++; + s = code[pc]; + pc++; + t = code[pc]; + pc++; + u = code[pc]; + pc++; + v = code[pc]; + pc++; + w = code[pc]; + pc++; + x = code[pc]; + pc++; + y = code[pc]; + pc++; + z = code[pc]; + pc++; + va = to_typed_big_word(0, 0, 0, 0, 0, 0, a, b, c, d, e, f, g, h, i, j, k, l, m, + n, o, p, q, r, s, t, u, v, w, x, y, z); + push_word(va); + break; + case push27_opcode: + logger << "op push27" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + l = code[pc]; + pc++; + m = code[pc]; + pc++; + n = code[pc]; + pc++; + o = code[pc]; + pc++; + p = code[pc]; + pc++; + q = code[pc]; + pc++; + r = code[pc]; + pc++; + s = code[pc]; + pc++; + t = code[pc]; + pc++; + u = code[pc]; + pc++; + v = code[pc]; + pc++; + w = code[pc]; + pc++; + x = code[pc]; + pc++; + y = code[pc]; + pc++; + z = code[pc]; + pc++; + aa = code[pc]; + pc++; + va = to_typed_big_word(0, 0, 0, 0, 0, a, b, c, d, e, f, g, h, i, j, k, l, m, n, + o, p, q, r, s, t, u, v, w, x, y, z, aa); + push_word(va); + break; + case push28_opcode: + logger << "op push28" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + l = code[pc]; + pc++; + m = code[pc]; + pc++; + n = code[pc]; + pc++; + o = code[pc]; + pc++; + p = code[pc]; + pc++; + q = code[pc]; + pc++; + r = code[pc]; + pc++; + s = code[pc]; + pc++; + t = code[pc]; + pc++; + u = code[pc]; + pc++; + v = code[pc]; + pc++; + w = code[pc]; + pc++; + x = code[pc]; + pc++; + y = code[pc]; + pc++; + z = code[pc]; + pc++; + aa = code[pc]; + pc++; + ab = code[pc]; + pc++; + va = to_typed_big_word(0, 0, 0, 0, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, + p, q, r, s, t, u, v, w, x, y, z, aa, ab); + push_word(va); + break; + case push29_opcode: + logger << "op push29" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + l = code[pc]; + pc++; + m = code[pc]; + pc++; + n = code[pc]; + pc++; + o = code[pc]; + pc++; + p = code[pc]; + pc++; + q = code[pc]; + pc++; + r = code[pc]; + pc++; + s = code[pc]; + pc++; + t = code[pc]; + pc++; + u = code[pc]; + pc++; + v = code[pc]; + pc++; + w = code[pc]; + pc++; + x = code[pc]; + pc++; + y = code[pc]; + pc++; + z = code[pc]; + pc++; + aa = code[pc]; + pc++; + ab = code[pc]; + pc++; + ac = code[pc]; + pc++; + va = to_typed_big_word(0, 0, 0, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, + q, r, s, t, u, v, w, x, y, z, aa, ab, ac); + push_word(va); + break; + case push30_opcode: + logger << "op push30" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + l = code[pc]; + pc++; + m = code[pc]; + pc++; + n = code[pc]; + pc++; + o = code[pc]; + pc++; + p = code[pc]; + pc++; + q = code[pc]; + pc++; + r = code[pc]; + pc++; + s = code[pc]; + pc++; + t = code[pc]; + pc++; + u = code[pc]; + pc++; + v = code[pc]; + pc++; + w = code[pc]; + pc++; + x = code[pc]; + pc++; + y = code[pc]; + pc++; + z = code[pc]; + pc++; + aa = code[pc]; + pc++; + ab = code[pc]; + pc++; + ac = code[pc]; + pc++; + ad = code[pc]; + pc++; + va = to_typed_big_word(0, 0, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, + q, r, s, t, u, v, w, x, y, z, aa, ab, ac, ad); + push_word(va); + break; + case push31_opcode: + logger << "op push31" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + l = code[pc]; + pc++; + m = code[pc]; + pc++; + n = code[pc]; + pc++; + o = code[pc]; + pc++; + p = code[pc]; + pc++; + q = code[pc]; + pc++; + r = code[pc]; + pc++; + s = code[pc]; + pc++; + t = code[pc]; + pc++; + u = code[pc]; + pc++; + v = code[pc]; + pc++; + w = code[pc]; + pc++; + x = code[pc]; + pc++; + y = code[pc]; + pc++; + z = code[pc]; + pc++; + aa = code[pc]; + pc++; + ab = code[pc]; + pc++; + ac = code[pc]; + pc++; + ad = code[pc]; + pc++; + ae = code[pc]; + pc++; + va = to_typed_big_word(0, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, + q, r, s, t, u, v, w, x, y, z, aa, ab, ac, ad, ae); + push_word(va); + break; + case push32_opcode: + logger << "op push32" << std::endl; + a = code[pc]; + pc++; + b = code[pc]; + pc++; + c = code[pc]; + pc++; + d = code[pc]; + pc++; + e = code[pc]; + pc++; + f = code[pc]; + pc++; + g = code[pc]; + pc++; + h = code[pc]; + pc++; + i = code[pc]; + pc++; + j = code[pc]; + pc++; + k = code[pc]; + pc++; + l = code[pc]; + pc++; + m = code[pc]; + pc++; + n = code[pc]; + pc++; + o = code[pc]; + pc++; + p = code[pc]; + pc++; + q = code[pc]; + pc++; + r = code[pc]; + pc++; + s = code[pc]; + pc++; + t = code[pc]; + pc++; + u = code[pc]; + pc++; + v = code[pc]; + pc++; + w = code[pc]; + pc++; + x = code[pc]; + pc++; + y = code[pc]; + pc++; + z = code[pc]; + pc++; + aa = code[pc]; + pc++; + ab = code[pc]; + pc++; + ac = code[pc]; + pc++; + ad = code[pc]; + pc++; + ae = code[pc]; + pc++; + af = code[pc]; + pc++; + va = to_typed_big_word(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, + q, r, s, t, u, v, w, x, y, z, aa, ab, ac, ad, ae, af); + push_word(va); + break; + case dup1_opcode: + logger << "op dup1" << std::endl; + va = stack.at(0); + push_word(va); + break; + case dup2_opcode: + logger << "op dup2" << std::endl; + va = stack.at(1); + push_word(va); + break; + case dup3_opcode: + logger << "op dup3" << std::endl; + va = stack.at(2); + push_word(va); + break; + case dup4_opcode: + logger << "op dup4" << std::endl; + va = stack.at(3); + push_word(va); + break; + case dup5_opcode: + logger << "op dup5" << std::endl; + va = stack.at(4); + push_word(va); + break; + case dup6_opcode: + logger << "op dup6" << std::endl; + va = stack.at(5); + push_word(va); + break; + case dup7_opcode: + logger << "op dup7" << std::endl; + va = stack.at(6); + push_word(va); + break; + case dup8_opcode: + logger << "op dup8" << std::endl; + va = stack.at(7); + push_word(va); + break; + case dup9_opcode: + logger << "op dup9" << std::endl; + va = stack.at(8); + push_word(va); + break; + case dup10_opcode: + logger << "op dup10" << std::endl; + va = stack.at(9); + push_word(va); + break; + case dup11_opcode: + logger << "op dup11" << std::endl; + va = stack.at(10); + push_word(va); + break; + case dup12_opcode: + logger << "op dup12" << std::endl; + va = stack.at(11); + push_word(va); + break; + case dup13_opcode: + logger << "op dup13" << std::endl; + va = stack.at(12); + push_word(va); + break; + case dup14_opcode: + logger << "op dup14" << std::endl; + va = stack.at(13); + push_word(va); + break; + case dup15_opcode: + logger << "op dup15" << std::endl; + va = stack.at(14); + push_word(va); + break; + case dup16_opcode: + logger << "op dup16" << std::endl; + va = stack.at(15); + push_word(va); + break; + case swap1_opcode: + logger << "op swap1" << std::endl; + va = pop_word(); + vb = pop_word(); + push_word(va); + push_word(vb); + break; + case swap2_opcode: + logger << "op swap2" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = pop_word(); + push_word(va); + push_word(vb); + push_word(vc); + break; + case swap3_opcode: + logger << "op swap3" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = pop_word(); + vd = pop_word(); + push_word(va); + push_word(vc); + push_word(vb); + push_word(vd); + break; + case swap4_opcode: + logger << "op swap4" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = pop_word(); + vd = pop_word(); + ve = pop_word(); + push_word(va); + push_word(vd); + push_word(vc); + push_word(vb); + push_word(ve); + break; + case swap5_opcode: + logger << "op swap5" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = pop_word(); + vd = pop_word(); + ve = pop_word(); + vf = pop_word(); + push_word(va); + push_word(ve); + push_word(vd); + push_word(vc); + push_word(vb); + push_word(vf); + break; + case swap6_opcode: + logger << "op swap6" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = pop_word(); + vd = pop_word(); + ve = pop_word(); + vf = pop_word(); + vg = pop_word(); + push_word(va); + push_word(vf); + push_word(ve); + push_word(vd); + push_word(vc); + push_word(vb); + push_word(vg); + break; + case swap7_opcode: + logger << "op swap7" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = pop_word(); + vd = pop_word(); + ve = pop_word(); + vf = pop_word(); + vg = pop_word(); + vh = pop_word(); + push_word(va); + push_word(vg); + push_word(vf); + push_word(ve); + push_word(vd); + push_word(vc); + push_word(vb); + push_word(vh); + break; + case swap8_opcode: + logger << "op swap8" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = pop_word(); + vd = pop_word(); + ve = pop_word(); + vf = pop_word(); + vg = pop_word(); + vh = pop_word(); + vi = pop_word(); + push_word(va); + push_word(vh); + push_word(vg); + push_word(vf); + push_word(ve); + push_word(vd); + push_word(vc); + push_word(vb); + push_word(vi); + break; + case swap9_opcode: + logger << "op swap9" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = pop_word(); + vd = pop_word(); + ve = pop_word(); + vf = pop_word(); + vg = pop_word(); + vh = pop_word(); + vi = pop_word(); + vj = pop_word(); + push_word(va); + push_word(vi); + push_word(vh); + push_word(vg); + push_word(vf); + push_word(ve); + push_word(vd); + push_word(vc); + push_word(vb); + push_word(vj); + break; + case swap10_opcode: + logger << "op swap10" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = pop_word(); + vd = pop_word(); + ve = pop_word(); + vf = pop_word(); + vg = pop_word(); + vh = pop_word(); + vi = pop_word(); + vj = pop_word(); + vk = pop_word(); + push_word(va); + push_word(vj); + push_word(vi); + push_word(vh); + push_word(vg); + push_word(vf); + push_word(ve); + push_word(vd); + push_word(vc); + push_word(vb); + push_word(vk); + break; + case swap11_opcode: + logger << "op swap11" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = pop_word(); + vd = pop_word(); + ve = pop_word(); + vf = pop_word(); + vg = pop_word(); + vh = pop_word(); + vi = pop_word(); + vj = pop_word(); + vk = pop_word(); + vl = pop_word(); + push_word(va); + push_word(vk); + push_word(vj); + push_word(vi); + push_word(vh); + push_word(vg); + push_word(vf); + push_word(ve); + push_word(vd); + push_word(vc); + push_word(vb); + push_word(vl); + break; + case swap12_opcode: + logger << "op swap12" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = pop_word(); + vd = pop_word(); + ve = pop_word(); + vf = pop_word(); + vg = pop_word(); + vh = pop_word(); + vi = pop_word(); + vj = pop_word(); + vk = pop_word(); + vl = pop_word(); + vm = pop_word(); + push_word(va); + push_word(vl); + push_word(vk); + push_word(vj); + push_word(vi); + push_word(vh); + push_word(vg); + push_word(vf); + push_word(ve); + push_word(vd); + push_word(vc); + push_word(vb); + push_word(vm); + break; + case swap13_opcode: + logger << "op swap13" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = pop_word(); + vd = pop_word(); + ve = pop_word(); + vf = pop_word(); + vg = pop_word(); + vh = pop_word(); + vi = pop_word(); + vj = pop_word(); + vk = pop_word(); + vl = pop_word(); + vm = pop_word(); + vn = pop_word(); + push_word(va); + push_word(vm); + push_word(vl); + push_word(vk); + push_word(vj); + push_word(vi); + push_word(vh); + push_word(vg); + push_word(vf); + push_word(ve); + push_word(vd); + push_word(vc); + push_word(vb); + push_word(vn); + break; + case swap14_opcode: + logger << "op swap14" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = pop_word(); + vd = pop_word(); + ve = pop_word(); + vf = pop_word(); + vg = pop_word(); + vh = pop_word(); + vi = pop_word(); + vj = pop_word(); + vk = pop_word(); + vl = pop_word(); + vm = pop_word(); + vn = pop_word(); + vo = pop_word(); + push_word(va); + push_word(vn); + push_word(vm); + push_word(vl); + push_word(vk); + push_word(vj); + push_word(vi); + push_word(vh); + push_word(vg); + push_word(vf); + push_word(ve); + push_word(vd); + push_word(vc); + push_word(vb); + push_word(vo); + break; + case swap15_opcode: + logger << "op swap15" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = pop_word(); + vd = pop_word(); + ve = pop_word(); + vf = pop_word(); + vg = pop_word(); + vh = pop_word(); + vi = pop_word(); + vj = pop_word(); + vk = pop_word(); + vl = pop_word(); + vm = pop_word(); + vn = pop_word(); + vo = pop_word(); + vp = pop_word(); + push_word(va); + push_word(vo); + push_word(vn); + push_word(vm); + push_word(vl); + push_word(vk); + push_word(vj); + push_word(vi); + push_word(vh); + push_word(vg); + push_word(vf); + push_word(ve); + push_word(vd); + push_word(vc); + push_word(vb); + push_word(vp); + break; + case swap16_opcode: + logger << "op swap16" << std::endl; + va = pop_word(); + vb = pop_word(); + vc = pop_word(); + vd = pop_word(); + ve = pop_word(); + vf = pop_word(); + vg = pop_word(); + vh = pop_word(); + vi = pop_word(); + vj = pop_word(); + vk = pop_word(); + vl = pop_word(); + vm = pop_word(); + vn = pop_word(); + vo = pop_word(); + vp = pop_word(); + vq = pop_word(); + push_word(va); + push_word(vp); + push_word(vo); + push_word(vn); + push_word(vm); + push_word(vl); + push_word(vk); + push_word(vj); + push_word(vi); + push_word(vh); + push_word(vg); + push_word(vf); + push_word(ve); + push_word(vd); + push_word(vc); + push_word(vb); + push_word(vq); + break; + case log0_opcode: + { + logger << "op log0" << std::endl; + va = pop_word(); // offset + vb = pop_word(); // length + offset = static_cast(va.value); + length = static_cast(vb.value); + std::vector slice; + slice.resize(length); + for (size_t i = 0; i < length; i++) { + slice[i] = memory[offset + i].value; + } + const log_object o = { slice, {} }; + this->emit_log(o); + break; + } + case log1_opcode: + { + logger << "op log1" << std::endl; + va = pop_word(); // offset + vb = pop_word(); // length + offset = static_cast(va.value); + length = static_cast(vb.value); + std::vector slice; + slice.resize(length); + for (size_t i = 0; i < length; i++) { + slice[i] = memory[offset + i].value; + } + + std::vector topics; + + topics.push_back( pop_word().value ); + + const log_object o = { slice, topics }; + this->emit_log(o); + break; + } + case log2_opcode: + { + logger << "op log2" << std::endl; + va = pop_word(); // offset + vb = pop_word(); // length + offset = static_cast(va.value); + length = static_cast(vb.value); + std::vector slice; + slice.resize(length); + for (size_t i = 0; i < length; i++) { + slice[i] = memory[offset + i].value; + } + + std::vector topics; + + for (size_t i = 0; i < 2; i++) { + topics.push_back( pop_word().value ); + } + + const log_object o = { slice, topics }; + this->emit_log(o); + break; + } + case log3_opcode: + { + logger << "op log3" << std::endl; + va = pop_word(); // offset + vb = pop_word(); // length + offset = static_cast(va.value); + length = static_cast(vb.value); + std::vector slice; + slice.resize(length); + for (size_t i = 0; i < length; i++) { + slice[i] = memory[offset + i].value; + } + + std::vector topics; + + for (size_t i = 0; i < 3; i++) { + topics.push_back( pop_word().value ); + } + + const log_object o = { slice, topics }; + this->emit_log(o); + break; + } + case log4_opcode: + { + logger << "op log4" << std::endl; + va = pop_word(); // offset + vb = pop_word(); // length + offset = static_cast(va.value); + length = static_cast(vb.value); + std::vector slice; + slice.resize(length); + for (size_t i = 0; i < length; i++) { + slice[i] = memory[offset + i].value; + } + + std::vector topics; + + for (size_t i = 0; i < 4; i++) { + topics.push_back( pop_word().value ); + } + + const log_object o = { slice, topics }; + this->emit_log(o); + break; + } + case create_opcode: + logger << "op create" << std::endl; + va = pop_word(); // value + vb = pop_word(); // offset + vc = pop_word(); // length + + for (size_t i = static_cast(vb.value); i < static_cast(vb.value) + static_cast(vc.value); i++) { + std::map::iterator it; + it = memory.find(i); + if (it != memory.end()) { + retval.push_back(it->second.value); + } + else { + retval.push_back(word(0)); + } + } + + push_word( typed_big_word( adapter.contract_create( retval, va.value ) ) ); // addr + break; + case call_opcode: + logger << "op call" << std::endl; + va = pop_word(); // energy + + vb = pop_word(); // address + vc = pop_word(); // value + vd = pop_word(); // argsOffset + ve = pop_word(); // argsLength + vf = pop_word(); // retOffset + vg = pop_word(); // retLength + + for (size_t i = static_cast(vd.value); i < static_cast(vd.value) + static_cast(ve.value); i++) { + std::map::iterator it; + it = memory.find(i); + if (it != memory.end()) { + contract_args.push_back(it->second.value); + } + else { + contract_args.push_back(word(0)); + } + } + + contract_call_return = adapter.contract_call(vb.value, static_cast(va.value), vc.value, contract_args); + + if (contract_call_return.second.size() > 0) { + ext_return_data = contract_call_return.second; + + for (size_t i = 0; i < static_cast(vf.value); i++) + memory[static_cast(ve.value) + i] = contract_call_return.second[i]; + } + + push_word(typed_big_word(contract_call_return.first)); + break; + case callcode_opcode: + logger << "op callcode" << std::endl; + va = pop_word(); // energy + + vb = pop_word(); // address + vc = pop_word(); // value + vd = pop_word(); // argsOffset + ve = pop_word(); // argsLength + vf = pop_word(); // retOffset + vg = pop_word(); // retLength + + for (size_t i = static_cast(vd.value); i < static_cast(vd.value) + static_cast(ve.value); i++) { + std::map::iterator it; + it = memory.find(i); + if (it != memory.end()) { + contract_args.push_back(it->second.value); + } + else { + contract_args.push_back(word(0)); + } + } + + contract_call_return = adapter.contract_callcode(vb.value, static_cast(va.value), vc.value, contract_args); + + if (contract_call_return.second.size() > 0) { + ext_return_data = contract_call_return.second; + + for (size_t i = 0; i < static_cast(vf.value); i++) + memory[static_cast(ve.value) + i] = contract_call_return.second[i]; + } + + push_word(typed_big_word(contract_call_return.first)); + break; + case return_opcode: + logger << "op return" << std::endl; + va = pop_word(); // offset + vb = pop_word(); // length + + for (size_t i = static_cast(va.value); i < static_cast(va.value + vb.value); i++) { + std::map::iterator it; + it = memory.find(i); + if (it != memory.end()) { + retval.push_back(it->second.value); + } + else { + retval.push_back(word(0)); + } + } + + return_value = retval; + adapter.contract_return( retval ); + state = machine_state::stopped; + break; + case delegatecall_opcode: + logger << "op delegatecall" << std::endl; + va = pop_word(); // energy + vb = pop_word(); // addr + vc = pop_word(); // argsOffset + vd = pop_word(); // argsLength + ve = pop_word(); // retOffset + vf = pop_word(); // retLength + + for (size_t i = static_cast(vc.value); i < static_cast(vc.value) + static_cast(vd.value); i++) { + std::map::iterator it; + it = memory.find(i); + if (it != memory.end()) { + contract_args.push_back(it->second.value); + } + else { + contract_args.push_back(word(0)); + } + } + + contract_call_return = adapter.contract_delegatecall(vb.value, static_cast(va.value), contract_args); + + if (contract_call_return.second.size() > 0) { + ext_return_data = contract_call_return.second; + + for (size_t i = 0; i < static_cast(vf.value); i++) + memory[static_cast(ve.value) + i] = contract_call_return.second[i]; + } + + push_word( typed_big_word(contract_call_return.first) ); + break; + case create2_opcode: + logger << "op create2" << std::endl; + va = pop_word(); // value + vb = pop_word(); // offset + vc = pop_word(); // length + vd = pop_word(); // salt + + for (size_t i = static_cast(vb.value); i < static_cast(vb.value) + static_cast(vc.value); i++) { + std::map::iterator it; + it = memory.find(i); + if (it != memory.end()) { + if ( it->second.is_sparse ) { + for (size_t i = 0; i < 31; i++) { + contract_args.push_back( word(0) ); + } + } + contract_args.push_back( word(it->second.value) ); + } + else { + if ( it->second.is_sparse ) { + for (size_t i = 0; i < 32; i++) { + contract_args.push_back( word(0) ); + } + } else { + contract_args.push_back( word(0) ); + } + } + } + + push_word( typed_big_word( adapter.contract_create2( contract_args, va.value, vd.value ) ) ); + + break; + case staticcall_opcode: + logger << "op staticcall" << std::endl; + va = pop_word(); // energy + + vb = pop_word(); // address + vc = pop_word(); // argsOffset + vd = pop_word(); // argsLength + ve = pop_word(); // retOffset + vf = pop_word(); // retLength + + for (size_t i = static_cast(vc.value); i < static_cast(vc.value) + static_cast(vd.value); i++) { + std::map::iterator it; + it = memory.find(i); + if (it != memory.end()) { + contract_args.push_back(it->second.value); + } + else { + contract_args.push_back(word(0)); + } + } + + contract_call_return = adapter.contract_staticcall(vb.value, static_cast(va.value), contract_args); + + ext_return_data = contract_call_return.second; + + for (size_t i = 0; i < static_cast(vf.value); i++) + memory[static_cast(ve.value) + i] = contract_call_return.second[i]; + + push_word(typed_big_word(contract_call_return.first)); + break; + case revert_opcode: + logger << "op revert" << std::endl; + va = pop_word(); // offset + vb = pop_word(); // length + + for (size_t i = static_cast(va.value); i < static_cast(vb.value); i++) { + std::map::iterator it; + it = memory.find(i); + if (it != memory.end()) { + retval.push_back(it->second.value); + } + else { + retval.push_back(word(0)); + } + memory[i] = 0; + } + return_value = retval; + adapter.revert( retval ); + state = machine_state::stopped; + break; + case invalid_opcode: + logger << "op invalid" << std::endl; + break; + case selfdestruct_opcode: + logger << "op selfdestruct" << std::endl; + va = stack.front(); // addr + adapter.self_destruct(va.value); + break; + } + } + + machine_state machine::get_state() + { + return state; + } + + boost::optional machine::get_error_message() + { + return error_message; + } + + std::stringstream& machine::get_logger() + { + return logger; + } + + std::vector& machine::get_return_value() + { + return return_value; + } + + bool machine::is_running() + { + return state == machine_state::running; + } + + std::string machine::to_json() + { + std::stringstream s; + s << "{"; + { + s << "\"finalState\":" << "{"; + { + s << "\"pc\":" << std::hex << pc << ","; + s << "\"stack\":" << "["; + for (auto it = stack.cbegin(); it != stack.cend(); ++it) + { + typed_big_word bw = *it; + s << bw.value; + s << ":"; + s << bw.is_sparse; + if (stack.size() > 1 && std::next(it, 1) != stack.cend()) + s << ","; + } + s << "],"; + s << "\"returnValue\":" << "["; + for (auto it = return_value.cbegin(); it != return_value.cend(); ++it) + { + word w = *it; + s << std::to_string(w); + if (return_value.size() > 1 && std::next(it, 1) != return_value.cend()) + s << ","; + } + s << "],"; + + s << "\"machineState\":\""; + switch (state) { + case machine_state::stopped: + s << "stopped"; + break; + case machine_state::running: + s << "running"; + break; + case machine_state::error: + s << "error"; + break; + default: + s << "unknown"; + } + s << "\","; + + if (code.size() != 0) { + word current_instruction = code[pc]; + opcode op = (opcode)current_instruction; + s << "\"opcode\":" << std::hex << op << ","; + } else { + s << "\"opcode\":null,"; + } + + if (error_message == boost::none) + s << "\"exceptionError\":" << "null"; + else + s << "\"exceptionError\":" << "\"" << error_message.value() << "\""; + s << ","; + + s << "\"memory\":" << "{"; + for (auto it = memory.cbegin(); it != memory.cend(); ++it) + { + s << "\"" << it->first << "\""; + s << ":"; + s << unsigned(it->second.value); + s << " : "; + s << it->second.is_sparse; + if (memory.size() > 1 && std::next(it, 1) != memory.cend()) + s << ","; + } + } + s << "}"; + } + s << "}"; + return s.str(); + } + + void machine::emit_log(const log_object& o) + { + } +} diff --git a/libraries/vendor/xgtvm/libraries/machine.hpp b/libraries/vendor/xgtvm/libraries/machine.hpp new file mode 100644 index 00000000..d36bc4a7 --- /dev/null +++ b/libraries/vendor/xgtvm/libraries/machine.hpp @@ -0,0 +1,583 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace machine +{ + typedef uint8_t word; + typedef boost::multiprecision::uint256_t big_word; + typedef boost::multiprecision::int256_t signed_big_word; + + struct typed_word + { + word value; + bool is_sparse; + + typed_word(const word _value = 0) : value(_value), is_sparse(false) {} + typed_word(const word _value, const bool _is_sparse) : value(_value), is_sparse(_is_sparse) {} + + bool operator==(const typed_word &other) const { + return this->value == other.value; + } + + bool operator!=(const typed_word &other) const { + return !(*this == other); + } + + bool operator<(const typed_word &other) const { + return this->value < other.value; + } + + bool operator>(const typed_word &other) const { + return this->value > other.value; + } + + typed_word operator+(const typed_word &rhs) const { + return typed_word(this->value + rhs.value); + } + + typed_word operator-(const typed_word &rhs) const { + return typed_word(this->value - rhs.value); + } + + typed_word operator*(const typed_word &rhs) const { + return typed_word(this->value * rhs.value); + } + + typed_word operator/(const typed_word &rhs) const { + return typed_word(this->value / rhs.value); + } + + typed_word operator%(const typed_word &rhs) const { + return typed_word(this->value % rhs.value); + } + + typed_word operator=(const typed_word &rhs) { + if (this == &rhs) + return *this; + this->value = rhs.value; + this->is_sparse = rhs.is_sparse; + return *this; + } + + typed_word operator+=(const typed_word &rhs) { + this->value = this->value+ rhs.value; + return *this; + } + + typed_word operator-=(const typed_word &rhs) { + this->value = this->value - rhs.value; + return *this; + } + + typed_word operator*=(const typed_word &rhs) { + this->value = this->value * rhs.value; + return *this; + } + + typed_word operator/=(const typed_word &rhs) { + this->value = this->value / rhs.value; + return *this; + } + + typed_word operator&(const typed_word &other) const { + return typed_word(this->value & other.value); + } + + typed_word operator|(const typed_word &other) const { + return typed_word(this->value | other.value); + } + + typed_word operator^(const typed_word &other) const { + return typed_word(this->value ^ other.value); + } + + typed_word operator~() const { + return typed_word(~this->value); + } + }; + + struct typed_big_word + { + big_word value; + bool is_sparse; + + typed_big_word(const big_word _value = 0) : value(_value), is_sparse(false) {} + typed_big_word(const big_word _value, const bool _is_sparse) : value(_value), is_sparse(_is_sparse) {} + + bool operator==(const typed_big_word &other) const { + return this->value == other.value; + } + + bool operator!=(const typed_big_word &other) const { + return !(*this == other); + } + + bool operator<(const typed_big_word &other) const { + return this->value < other.value; + } + + bool operator>(const typed_big_word &other) const { + return this->value > other.value; + } + + typed_big_word operator+(const typed_big_word &rhs) const { + return typed_big_word(this->value + rhs.value); + } + + typed_big_word operator-(const typed_big_word &rhs) const { + return typed_big_word(this->value - rhs.value); + } + + typed_big_word operator*(const typed_big_word &rhs) const { + return typed_big_word(this->value * rhs.value); + } + + typed_big_word operator/(const typed_big_word &rhs) const { + return typed_big_word(this->value / rhs.value); + } + + typed_big_word operator%(const typed_big_word &rhs) const { + return typed_big_word(this->value % rhs.value); + } + + typed_big_word operator=(const typed_big_word &rhs) { + if (this == &rhs) + return *this; + this->value = rhs.value; + this->is_sparse = rhs.is_sparse; + return *this; + } + + typed_big_word operator+=(const typed_big_word &rhs) { + this->value = this->value + rhs.value; + return *this; + } + + typed_big_word operator-=(const typed_big_word &rhs) { + this->value = this->value - rhs.value; + return *this; + } + + typed_big_word operator*=(const typed_big_word &rhs) { + this->value = this->value * rhs.value; + return *this; + } + + typed_big_word operator/=(const typed_big_word &rhs) { + this->value = this->value / rhs.value; + return *this; + } + + typed_big_word operator&(const typed_big_word &other) const { + return typed_big_word(this->value & other.value); + } + + typed_big_word operator|(const typed_big_word &other) const { + return typed_big_word(this->value | other.value); + } + + typed_big_word operator^(const typed_big_word &other) const { + return typed_big_word(this->value ^ other.value); + } + + typed_big_word operator~() const { + return typed_big_word(~this->value); + } + }; + + struct typed_signed_big_word + { + signed_big_word value; + bool is_sparse; + + typed_signed_big_word(const signed_big_word _value = 0) : value(_value), is_sparse(false) {} + typed_signed_big_word(const signed_big_word _value, const bool _is_sparse) : value(_value), is_sparse(_is_sparse) {} + + bool operator==(const typed_signed_big_word &other) const { + return this->value == other.value; + } + + bool operator!=(const typed_signed_big_word &other) const { + return !(*this == other); + } + + bool operator<(const typed_signed_big_word &other) const { + return this->value < other.value; + } + + bool operator>(const typed_signed_big_word &other) const { + return this->value > other.value; + } + + typed_signed_big_word operator+(const typed_signed_big_word &rhs) const { + return typed_signed_big_word(this->value + rhs.value); + } + + typed_signed_big_word operator-(const typed_signed_big_word &rhs) const { + return typed_signed_big_word(this->value - rhs.value); + } + + typed_signed_big_word operator*(const typed_signed_big_word &rhs) const { + return typed_signed_big_word(this->value * rhs.value); + } + + typed_signed_big_word operator/(const typed_signed_big_word &rhs) const { + return typed_signed_big_word(this->value / rhs.value); + } + + typed_signed_big_word operator%(const typed_signed_big_word &rhs) const { + return typed_signed_big_word(this->value % rhs.value); + } + + typed_signed_big_word operator=(const typed_signed_big_word &rhs) { + if (this == &rhs) + return *this; + this->value = rhs.value; + this->is_sparse = rhs.is_sparse; + return *this; + } + + typed_signed_big_word operator+=(const typed_signed_big_word &rhs) { + this->value = this->value + rhs.value; + return *this; + } + + typed_signed_big_word operator-=(const typed_signed_big_word &rhs) { + this->value = this->value - rhs.value; + return *this; + } + + typed_signed_big_word operator*=(const typed_signed_big_word &rhs) { + this->value = this->value * rhs.value; + return *this; + } + + typed_signed_big_word operator/=(const typed_signed_big_word &rhs) { + this->value = this->value / rhs.value; + return *this; + } + + typed_signed_big_word operator&(const typed_signed_big_word &other) const { + return typed_signed_big_word(this->value & other.value); + } + + typed_signed_big_word operator|(const typed_signed_big_word &other) const { + return typed_signed_big_word(this->value | other.value); + } + + typed_signed_big_word operator^(const typed_signed_big_word &other) const { + return typed_signed_big_word(this->value ^ other.value); + } + + typed_signed_big_word operator~() const { + return typed_signed_big_word(~this->value); + } + }; + + enum opcode + { + // ARITHMETIC + stop_opcode = 0x00, + add_opcode = 0x01, + mul_opcode = 0x02, + sub_opcode = 0x03, + div_opcode = 0x04, + sdiv_opcode = 0x05, + mod_opcode = 0x06, + smod_opcode = 0x07, + addmod_opcode = 0x08, + mulmod_opcode = 0x09, + exp_opcode = 0x0a, + + signextend_opcode = 0x0b, + + // COMPARISON + lt_opcode = 0x10, + gt_opcode = 0x11, + slt_opcode = 0x12, + sgt_opcode = 0x13, + eq_opcode = 0x14, + iszero_opcode = 0x15, + + // BITWISE + and_opcode = 0x16, + or_opcode = 0x17, + xor_opcode = 0x18, + not_opcode = 0x19, + byte_opcode = 0x1A, + shl_opcode = 0x1B, + shr_opcode = 0x1C, + sar_opcode = 0x1D, + + sha3_opcode = 0x20, + address_opcode = 0x30, + balance_opcode = 0x31, + origin_opcode = 0x32, + caller_opcode = 0x33, + callvalue_opcode = 0x34, + calldataload_opcode = 0x35, + calldatasize_opcode = 0x36, + calldatacopy_opcode = 0x37, + codesize_opcode = 0x38, + codecopy_opcode = 0x39, + energyprice_opcode = 0x3A, + extcodesize_opcode = 0x3B, + extcodecopy_opcode = 0x3C, + returndatasize_opcode = 0x3D, + returndatacopy_opcode = 0x3E, + extcodehash_opcode = 0x3F, + blockhash_opcode = 0x40, + coinbase_opcode = 0x41, + timestamp_opcode = 0x42, + number_opcode = 0x43, + difficulty_opcode = 0x44, + energylimit_opcode = 0x45, + selfbalance_opcode = 0x47, + pop_opcode = 0x50, + mload_opcode = 0x51, + mstore_opcode = 0x52, + mstore8_opcode = 0x53, + sload_opcode = 0x54, + sstore_opcode = 0x55, + jump_opcode = 0x56, + jumpi_opcode = 0x57, + pc_opcode = 0x58, + msize_opcode = 0x59, + energy_opcode = 0x5A, + jumpdest_opcode = 0x5B, + + // PUSH + push1_opcode = 0x60, + push2_opcode = 0x61, + push3_opcode = 0x62, + push4_opcode = 0x63, + push5_opcode = 0x64, + push6_opcode = 0x65, + push7_opcode = 0x66, + push8_opcode = 0x67, + push9_opcode = 0x68, + push10_opcode = 0x69, + push11_opcode = 0x6A, + push12_opcode = 0x6B, + push13_opcode = 0x6C, + push14_opcode = 0x6D, + push15_opcode = 0x6E, + push16_opcode = 0x6F, + push17_opcode = 0x70, + push18_opcode = 0x71, + push19_opcode = 0x72, + push20_opcode = 0x73, + push21_opcode = 0x74, + push22_opcode = 0x75, + push23_opcode = 0x76, + push24_opcode = 0x77, + push25_opcode = 0x78, + push26_opcode = 0x79, + push27_opcode = 0x7A, + push28_opcode = 0x7B, + push29_opcode = 0x7C, + push30_opcode = 0x7D, + push31_opcode = 0x7E, + push32_opcode = 0x7F, + + // DUP + dup1_opcode = 0x80, + dup2_opcode = 0x81, + dup3_opcode = 0x82, + dup4_opcode = 0x83, + dup5_opcode = 0x84, + dup6_opcode = 0x85, + dup7_opcode = 0x86, + dup8_opcode = 0x87, + dup9_opcode = 0x88, + dup10_opcode = 0x89, + dup11_opcode = 0x8A, + dup12_opcode = 0x8B, + dup13_opcode = 0x8C, + dup14_opcode = 0x8D, + dup15_opcode = 0x8E, + dup16_opcode = 0x8F, + + // SWAP + swap1_opcode = 0x90, + swap2_opcode = 0x91, + swap3_opcode = 0x92, + swap4_opcode = 0x93, + swap5_opcode = 0x94, + swap6_opcode = 0x95, + swap7_opcode = 0x96, + swap8_opcode = 0x97, + swap9_opcode = 0x98, + swap10_opcode = 0x99, + swap11_opcode = 0x9A, + swap12_opcode = 0x9B, + swap13_opcode = 0x9C, + swap14_opcode = 0x9D, + swap15_opcode = 0x9E, + swap16_opcode = 0x9F, + + // LOG + log0_opcode = 0xA0, + log1_opcode = 0xA1, + log2_opcode = 0xA2, + log3_opcode = 0xA3, + log4_opcode = 0xA4, + + create_opcode = 0xF0, + call_opcode = 0xF1, + callcode_opcode = 0xF2, + return_opcode = 0xF3, + delegatecall_opcode = 0xF4, + create2_opcode = 0xF5, + staticcall_opcode = 0xFA, + revert_opcode = 0xFD, + invalid_opcode = 0xFE, + selfdestruct_opcode = 0xFF, + }; + + enum class machine_state + { + stopped, + running, + error + }; + + struct log_object + { + std::vector data; + std::vector topics; + }; + + struct message + { + uint32_t flags; + int32_t depth; + int64_t energy; + + big_word sender; + big_word destination; + + uint64_t value; + size_t input_size; + std::vector input_data = {}; + size_t code_size; + }; + + // TODO ensure correct data types + struct context + { + bool is_debug; + uint64_t block_timestamp; + uint64_t block_number; + uint64_t block_difficulty; + uint64_t block_energylimit; + int64_t tx_energyprice; + big_word tx_origin; + big_word block_coinbase; + }; + + struct chain_adapter + { + // TODO sha3 opcode + std::function< big_word(std::vector) > sha3; + + std::function< big_word(big_word) > get_balance; + + // TODO for hashing address -- extcodehash opcode + std::function< big_word(big_word) > get_code_hash; + + // TODO for hashing block number -- blockhash opcode + std::function< machine::big_word(uint64_t) > get_block_hash; + + // TODO get contract bytecode at address + std::function< std::vector(big_word) > get_code_at_addr; + + // TODO creates a child contract -- create opcode + std::function< big_word(std::vector, big_word) > contract_create; + + // TODO call a method from another contract -- call opcode -- address, energy, value, args + std::function< std::pair< word, std::vector >(big_word, uint64_t, big_word, std::vector) > contract_call; + + // TODO call a method from another contract(?) -- callcode opcode -- address, energy, value, args + std::function< std::pair< word, std::vector >(big_word, uint64_t, big_word, std::vector) > contract_callcode; + + // TODO call a method from another contract using the storage of the current + // opcode -- delegatecall opcode -- address, energy, args + std::function< std::pair< word, std::vector >(big_word, uint64_t, std::vector) > contract_delegatecall; + + // TODO call a method from another contract with state changes disallowed -- staticcall opcode -- address, energy, args + std::function< std::pair< word, std::vector >(big_word, uint64_t, std::vector) > contract_staticcall; + + // TODO creates a child contract -- create2 opcode + std::function< big_word(std::vector, big_word, big_word) > contract_create2; + + // TODO revert opcode + std::function< bool(std::vector) > revert; + + // TODO load opcode -- takes key as a parameter and returns value + std::function< big_word(big_word) > get_storage; + + // TODO sstore opcode -- destination, key, value + std::function< void(big_word, big_word) > set_storage; + + // TODO return opcode + std::function< std::vector(std::vector) > contract_return; + + // TODO selfdestruct opcode + std::function< bool(big_word) > self_destruct; + + std::function< void(const log_object&) > emit_log; + }; + + class machine + { + size_t pc = 0; + std::deque stack; + machine_state state = machine_state::running; + context ctx; + std::vector code; + message msg; + std::map memory; + std::map storage; + std::vector return_value; + std::vector ext_return_data; + boost::optional error_message; + std::stringstream logger; + chain_adapter adapter; + typed_big_word energy_left; + opcode current_opcode = stop_opcode; + + void push_word(typed_big_word v); + typed_big_word pop_word(); + void log(std::string output); + + public: + machine(context ctx, std::vector code, message msg, chain_adapter adapter) + : ctx(ctx), code(code), msg(msg), adapter(adapter) + { + } + + typed_big_word peek_word(); + void print_stack(); + size_t stack_length(); + void step(); + bool is_running(); + std::vector& get_return_value(); + machine_state get_state(); + boost::optional get_error_message(); + std::stringstream& get_logger(); + opcode get_current_opcode() { return current_opcode; }; + std::string to_json(); + + void emit_log(const log_object& o); + }; +} diff --git a/libraries/vendor/xgtvm/lottery.bytecode b/libraries/vendor/xgtvm/lottery.bytecode new file mode 100644 index 00000000..991ce37f --- /dev/null +++ b/libraries/vendor/xgtvm/lottery.bytecode @@ -0,0 +1 @@ +608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610680806100606000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063481c6a75146100725780635d495aea146100c95780638b5b9ccc146100e0578063e97dcb621461014c578063f71d96cb14610156575b600080fd5b34801561007e57600080fd5b506100876101c3565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156100d557600080fd5b506100de6101e8565b005b3480156100ec57600080fd5b506100f5610340565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b8381101561013857808201518184015260208101905061011d565b505050509050019250505060405180910390f35b6101546103ce565b005b34801561016257600080fd5b506101816004803603810190808035906020019092919050505061044b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561024557600080fd5b600180549050610253610489565b81151561025c57fe5b06905060018181548110151561026e57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f193505050501580156102f5573d6000803e3d6000fd5b5060006040519080825280602002602001820160405280156103265781602001602082028038833980820191505090505b506001908051906020019061033c929190610587565b5050565b606060018054806020026020016040519081016040528092919081815260200182805480156103c457602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001906001019080831161037a575b5050505050905090565b662386f26fc10000341115156103e357600080fd5b60013390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60018181548110151561045a57fe5b906000526020600020016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60004442600160405160200180848152602001838152602001828054801561050657602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116104bc575b505093505050506040516020818303038152906040526040518082805190602001908083835b602083101515610551578051825260208201915060208101905060208303925061052c565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902060019004905090565b828054828255906000526020600020908101928215610600579160200282015b828111156105ff5782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550916020019190600101906105a7565b5b50905061060d9190610611565b5090565b61065191905b8082111561064d57600081816101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905550600101610617565b5090565b905600a165627a7a72305820919b1f329afa6406ac32ccc812f65d08dcb29f0c1b9fb63cf34e5abfdef8da070029 diff --git a/libraries/vendor/xgtvm/lottery.json b/libraries/vendor/xgtvm/lottery.json new file mode 100644 index 00000000..d2d88c9c --- /dev/null +++ b/libraries/vendor/xgtvm/lottery.json @@ -0,0 +1 @@ +[0x60, 0x80, 0x60, 0x40, 0x52, 0x34, 0x80, 0x15, 0x61, 0x00, 0x10, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x33, 0x60, 0x00, 0x80, 0x61, 0x01, 0x00, 0x0a, 0x81, 0x54, 0x81, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x19, 0x16, 0x90, 0x83, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x02, 0x17, 0x90, 0x55, 0x50, 0x61, 0x06, 0x80, 0x80, 0x61, 0x00, 0x60, 0x60, 0x00, 0x39, 0x60, 0x00, 0xf3, 0x00, 0x60, 0x80, 0x60, 0x40, 0x52, 0x60, 0x04, 0x36, 0x10, 0x61, 0x00, 0x6d, 0x57, 0x60, 0x00, 0x35, 0x7c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x04, 0x63, 0xff, 0xff, 0xff, 0xff, 0x16, 0x80, 0x63, 0x48, 0x1c, 0x6a, 0x75, 0x14, 0x61, 0x00, 0x72, 0x57, 0x80, 0x63, 0x5d, 0x49, 0x5a, 0xea, 0x14, 0x61, 0x00, 0xc9, 0x57, 0x80, 0x63, 0x8b, 0x5b, 0x9c, 0xcc, 0x14, 0x61, 0x00, 0xe0, 0x57, 0x80, 0x63, 0xe9, 0x7d, 0xcb, 0x62, 0x14, 0x61, 0x01, 0x4c, 0x57, 0x80, 0x63, 0xf7, 0x1d, 0x96, 0xcb, 0x14, 0x61, 0x01, 0x56, 0x57, 0x5b, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x34, 0x80, 0x15, 0x61, 0x00, 0x7e, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x00, 0x87, 0x61, 0x01, 0xc3, 0x56, 0x5b, 0x60, 0x40, 0x51, 0x80, 0x82, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0xf3, 0x5b, 0x34, 0x80, 0x15, 0x61, 0x00, 0xd5, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x00, 0xde, 0x61, 0x01, 0xe8, 0x56, 0x5b, 0x00, 0x5b, 0x34, 0x80, 0x15, 0x61, 0x00, 0xec, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x00, 0xf5, 0x61, 0x03, 0x40, 0x56, 0x5b, 0x60, 0x40, 0x51, 0x80, 0x80, 0x60, 0x20, 0x01, 0x82, 0x81, 0x03, 0x82, 0x52, 0x83, 0x81, 0x81, 0x51, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x80, 0x51, 0x90, 0x60, 0x20, 0x01, 0x90, 0x60, 0x20, 0x02, 0x80, 0x83, 0x83, 0x60, 0x00, 0x5b, 0x83, 0x81, 0x10, 0x15, 0x61, 0x01, 0x38, 0x57, 0x80, 0x82, 0x01, 0x51, 0x81, 0x84, 0x01, 0x52, 0x60, 0x20, 0x81, 0x01, 0x90, 0x50, 0x61, 0x01, 0x1d, 0x56, 0x5b, 0x50, 0x50, 0x50, 0x50, 0x90, 0x50, 0x01, 0x92, 0x50, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0xf3, 0x5b, 0x61, 0x01, 0x54, 0x61, 0x03, 0xce, 0x56, 0x5b, 0x00, 0x5b, 0x34, 0x80, 0x15, 0x61, 0x01, 0x62, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x01, 0x81, 0x60, 0x04, 0x80, 0x36, 0x03, 0x81, 0x01, 0x90, 0x80, 0x80, 0x35, 0x90, 0x60, 0x20, 0x01, 0x90, 0x92, 0x91, 0x90, 0x50, 0x50, 0x50, 0x61, 0x04, 0x4b, 0x56, 0x5b, 0x60, 0x40, 0x51, 0x80, 0x82, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0xf3, 0x5b, 0x60, 0x00, 0x80, 0x90, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x56, 0x5b, 0x60, 0x00, 0x80, 0x60, 0x00, 0x90, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x33, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x14, 0x15, 0x15, 0x61, 0x02, 0x45, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x60, 0x01, 0x80, 0x54, 0x90, 0x50, 0x61, 0x02, 0x53, 0x61, 0x04, 0x89, 0x56, 0x5b, 0x81, 0x15, 0x15, 0x61, 0x02, 0x5c, 0x57, 0xfe, 0x5b, 0x06, 0x90, 0x50, 0x60, 0x01, 0x81, 0x81, 0x54, 0x81, 0x10, 0x15, 0x15, 0x61, 0x02, 0x6e, 0x57, 0xfe, 0x5b, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x01, 0x60, 0x00, 0x90, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x61, 0x08, 0xfc, 0x30, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x31, 0x90, 0x81, 0x15, 0x02, 0x90, 0x60, 0x40, 0x51, 0x60, 0x00, 0x60, 0x40, 0x51, 0x80, 0x83, 0x03, 0x81, 0x85, 0x88, 0x88, 0xf1, 0x93, 0x50, 0x50, 0x50, 0x50, 0x15, 0x80, 0x15, 0x61, 0x02, 0xf5, 0x57, 0x3d, 0x60, 0x00, 0x80, 0x3e, 0x3d, 0x60, 0x00, 0xfd, 0x5b, 0x50, 0x60, 0x00, 0x60, 0x40, 0x51, 0x90, 0x80, 0x82, 0x52, 0x80, 0x60, 0x20, 0x02, 0x60, 0x20, 0x01, 0x82, 0x01, 0x60, 0x40, 0x52, 0x80, 0x15, 0x61, 0x03, 0x26, 0x57, 0x81, 0x60, 0x20, 0x01, 0x60, 0x20, 0x82, 0x02, 0x80, 0x38, 0x83, 0x39, 0x80, 0x82, 0x01, 0x91, 0x50, 0x50, 0x90, 0x50, 0x5b, 0x50, 0x60, 0x01, 0x90, 0x80, 0x51, 0x90, 0x60, 0x20, 0x01, 0x90, 0x61, 0x03, 0x3c, 0x92, 0x91, 0x90, 0x61, 0x05, 0x87, 0x56, 0x5b, 0x50, 0x50, 0x56, 0x5b, 0x60, 0x60, 0x60, 0x01, 0x80, 0x54, 0x80, 0x60, 0x20, 0x02, 0x60, 0x20, 0x01, 0x60, 0x40, 0x51, 0x90, 0x81, 0x01, 0x60, 0x40, 0x52, 0x80, 0x92, 0x91, 0x90, 0x81, 0x81, 0x52, 0x60, 0x20, 0x01, 0x82, 0x80, 0x54, 0x80, 0x15, 0x61, 0x03, 0xc4, 0x57, 0x60, 0x20, 0x02, 0x82, 0x01, 0x91, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x90, 0x5b, 0x81, 0x60, 0x00, 0x90, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x90, 0x60, 0x01, 0x01, 0x90, 0x80, 0x83, 0x11, 0x61, 0x03, 0x7a, 0x57, 0x5b, 0x50, 0x50, 0x50, 0x50, 0x50, 0x90, 0x50, 0x90, 0x56, 0x5b, 0x66, 0x23, 0x86, 0xf2, 0x6f, 0xc1, 0x00, 0x00, 0x34, 0x11, 0x15, 0x15, 0x61, 0x03, 0xe3, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x60, 0x01, 0x33, 0x90, 0x80, 0x60, 0x01, 0x81, 0x54, 0x01, 0x80, 0x82, 0x55, 0x80, 0x91, 0x50, 0x50, 0x90, 0x60, 0x01, 0x82, 0x03, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x01, 0x60, 0x00, 0x90, 0x91, 0x92, 0x90, 0x91, 0x90, 0x91, 0x61, 0x01, 0x00, 0x0a, 0x81, 0x54, 0x81, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x19, 0x16, 0x90, 0x83, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x02, 0x17, 0x90, 0x55, 0x50, 0x50, 0x56, 0x5b, 0x60, 0x01, 0x81, 0x81, 0x54, 0x81, 0x10, 0x15, 0x15, 0x61, 0x04, 0x5a, 0x57, 0xfe, 0x5b, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x01, 0x60, 0x00, 0x91, 0x50, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x56, 0x5b, 0x60, 0x00, 0x44, 0x42, 0x60, 0x01, 0x60, 0x40, 0x51, 0x60, 0x20, 0x01, 0x80, 0x84, 0x81, 0x52, 0x60, 0x20, 0x01, 0x83, 0x81, 0x52, 0x60, 0x20, 0x01, 0x82, 0x80, 0x54, 0x80, 0x15, 0x61, 0x05, 0x06, 0x57, 0x60, 0x20, 0x02, 0x82, 0x01, 0x91, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x90, 0x5b, 0x81, 0x60, 0x00, 0x90, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x90, 0x60, 0x01, 0x01, 0x90, 0x80, 0x83, 0x11, 0x61, 0x04, 0xbc, 0x57, 0x5b, 0x50, 0x50, 0x93, 0x50, 0x50, 0x50, 0x50, 0x60, 0x40, 0x51, 0x60, 0x20, 0x81, 0x83, 0x03, 0x03, 0x81, 0x52, 0x90, 0x60, 0x40, 0x52, 0x60, 0x40, 0x51, 0x80, 0x82, 0x80, 0x51, 0x90, 0x60, 0x20, 0x01, 0x90, 0x80, 0x83, 0x83, 0x5b, 0x60, 0x20, 0x83, 0x10, 0x15, 0x15, 0x61, 0x05, 0x51, 0x57, 0x80, 0x51, 0x82, 0x52, 0x60, 0x20, 0x82, 0x01, 0x91, 0x50, 0x60, 0x20, 0x81, 0x01, 0x90, 0x50, 0x60, 0x20, 0x83, 0x03, 0x92, 0x50, 0x61, 0x05, 0x2c, 0x56, 0x5b, 0x60, 0x01, 0x83, 0x60, 0x20, 0x03, 0x61, 0x01, 0x00, 0x0a, 0x03, 0x80, 0x19, 0x82, 0x51, 0x16, 0x81, 0x84, 0x51, 0x16, 0x80, 0x82, 0x17, 0x85, 0x52, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x90, 0x50, 0x01, 0x91, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0x20, 0x60, 0x01, 0x90, 0x04, 0x90, 0x50, 0x90, 0x56, 0x5b, 0x82, 0x80, 0x54, 0x82, 0x82, 0x55, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x90, 0x81, 0x01, 0x92, 0x82, 0x15, 0x61, 0x06, 0x00, 0x57, 0x91, 0x60, 0x20, 0x02, 0x82, 0x01, 0x5b, 0x82, 0x81, 0x11, 0x15, 0x61, 0x05, 0xff, 0x57, 0x82, 0x51, 0x82, 0x60, 0x00, 0x61, 0x01, 0x00, 0x0a, 0x81, 0x54, 0x81, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x19, 0x16, 0x90, 0x83, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x02, 0x17, 0x90, 0x55, 0x50, 0x91, 0x60, 0x20, 0x01, 0x91, 0x90, 0x60, 0x01, 0x01, 0x90, 0x61, 0x05, 0xa7, 0x56, 0x5b, 0x5b, 0x50, 0x90, 0x50, 0x61, 0x06, 0x0d, 0x91, 0x90, 0x61, 0x06, 0x11, 0x56, 0x5b, 0x50, 0x90, 0x56, 0x5b, 0x61, 0x06, 0x51, 0x91, 0x90, 0x5b, 0x80, 0x82, 0x11, 0x15, 0x61, 0x06, 0x4d, 0x57, 0x60, 0x00, 0x81, 0x81, 0x61, 0x01, 0x00, 0x0a, 0x81, 0x54, 0x90, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x19, 0x16, 0x90, 0x55, 0x50, 0x60, 0x01, 0x01, 0x61, 0x06, 0x17, 0x56, 0x5b, 0x50, 0x90, 0x56, 0x5b, 0x90, 0x56, 0x00, 0xa1, 0x65, 0x62, 0x7a, 0x7a, 0x72, 0x30, 0x58, 0x20, 0x91, 0x9b, 0x1f, 0x32, 0x9a, 0xfa, 0x64, 0x06, 0xac, 0x32, 0xcc, 0xc8, 0x12, 0xf6, 0x5d, 0x08, 0xdc, 0xb2, 0x9f, 0x0c, 0x1b, 0x9f, 0xb6, 0x3c, 0xf3, 0x4e, 0x5a, 0xbf, 0xde, 0xf8, 0xda, 0x07, 0x00, 0x29] diff --git a/libraries/vendor/xgtvm/lottery2.bytecode b/libraries/vendor/xgtvm/lottery2.bytecode new file mode 100644 index 00000000..3b0030f8 --- /dev/null +++ b/libraries/vendor/xgtvm/lottery2.bytecode @@ -0,0 +1 @@ +60806040523480156200001157600080fd5b506040516200175438038062001754833981018060405281019080805182019291906020018051906020019092919050505080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600090805190602001906200009c929190620000a5565b50505062000154565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620000e857805160ff191683800117855562000119565b8280016001018555821562000119579182015b8281111562000118578251825591602001919060010190620000fb565b5b5090506200012891906200012c565b5090565b6200015191905b808211156200014d57600081600090555060010162000133565b5090565b90565b6115f080620001646000396000f3006080604052600436106100d0576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806310c85fe51461011057806314034bd21461013f5780631d27769f1461015657806323d14149146101b2578063481c6a75146102425780635832d571146102995780635c12cd4b146103065780635d58a74a146103c95780637752045b146103f45780638b5b9ccc1461041f578063bdaea3261461048b578063d68895d8146104c2578063dfbf53ae146104ed578063f25266dd1461058b575b61010e6040805190810160405280600781526020017f556e6b6e6f776e000000000000000000000000000000000000000000000000008152506105f8565b005b34801561011c57600080fd5b506101256109ee565b604051808215151515815260200191505060405180910390f35b34801561014b57600080fd5b50610154610a01565b005b6101b0600480360381019080803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506105f8565b005b3480156101be57600080fd5b506101c7610dbf565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102075780820151818401526020810190506101ec565b50505050905090810190601f1680156102345780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561024e57600080fd5b50610257610e5d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156102a557600080fd5b506102c460048036038101908080359060200190929190505050610e83565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561031257600080fd5b50610347600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ec1565b6040518080602001838152602001828103825284818151815260200191508051906020019080838360005b8381101561038d578082015181840152602081019050610372565b50505050905090810190601f1680156103ba5780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b3480156103d557600080fd5b506103de61101e565b6040518082815260200191505060405180910390f35b34801561040057600080fd5b50610409611024565b6040518082815260200191505060405180910390f35b34801561042b57600080fd5b5061043461102a565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b8381101561047757808201518184015260208101905061045c565b505050509050019250505060405180910390f35b34801561049757600080fd5b506104c060048036038101908080359060200190929190803590602001909291905050506110b8565b005b3480156104ce57600080fd5b506104d7611161565b6040518082815260200191505060405180910390f35b3480156104f957600080fd5b50610502611180565b6040518080602001848152602001838152602001828103825285818151815260200191508051906020019080838360005b8381101561054e578082015181840152602081019050610533565b50505050905090810190601f16801561057b5780820380516001836020036101000a031916815260200191505b5094505050505060405180910390f35b34801561059757600080fd5b506105b660048036038101908080359060200190929190505050611230565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6000815111151561060857600080fd5b600860009054906101000a900460ff16151561062357600080fd5b670de0b6b3a7640000600a54023414151561063d57600080fd5b600954600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001015410151561068f57600080fd5b6106983361126e565b156107ef576001600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001018190555080600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001908051906020019061073b9291906113cb565b50600160023390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555003600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020181905550610841565b6001600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101600082825401925050819055505b60043390806001815401808255809150509060018203906000526020600020016000909192909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550507f76041b6e8130995874e79e751d284536c37242cb014fb0584ede1d1e64ce03c9600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001015460405180806020018381526020018281038252848181546001816001161561010002031660029004815260200191508054600181600116156101000203166002900480156109dc5780601f106109b1576101008083540402835291602001916109dc565b820191906000526020600020905b8154815290600101906020018083116109bf57829003601f168201915b5050935050505060405180910390a150565b600860009054906101000a900460ff1681565b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610a5f57600080fd5b6000600480549050111515610a7357600080fd5b600480549050610a81611339565b811515610a8a57fe5b069050600481815481101515610a9c57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f19350505050158015610b23573d6000803e3d6000fd5b5060036000600483815481101515610b3757fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160056000019080546001816001161561010002031660029004610bc392919061144b565b5060036000600483815481101515610bd757fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600101546005600101819055506000604051908082528060200260200182016040528015610c795781602001602082028038833980820191505090505b5060049080519060200190610c8f9291906114d2565b506000604051908082528060200260200182016040528015610cc05781602001602082028038833980820191505090505b5060029080519060200190610cd69291906114d2565b506000600860006101000a81548160ff0219169083151502179055507fd6d1eeba639254bd05e36261ae299af245328ab997fd9b7823d5fff17f1b74a460056000016005600101546040518080602001838152602001828103825284818154600181600116156101000203166002900481526020019150805460018160011615610100020316600290048015610dad5780601f10610d8257610100808354040283529160200191610dad565b820191906000526020600020905b815481529060010190602001808311610d9057829003601f168201915b5050935050505060405180910390a150565b60008054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610e555780601f10610e2a57610100808354040283529160200191610e55565b820191906000526020600020905b815481529060010190602001808311610e3857829003601f168201915b505050505081565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600281815481101515610e9257fe5b906000526020600020016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60606000610ece8361126e565b15610ef357600060206040519081016040528060008152509080905091509150611019565b600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010154818054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561100d5780601f10610fe25761010080835404028352916020019161100d565b820191906000526020600020905b815481529060010190602001808311610ff057829003601f168201915b50505050509150915091505b915091565b600a5481565b60095481565b606060028054806020026020016040519081016040528092919081815260200182805480156110ae57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611064575b5050505050905090565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561111457600080fd5b6001600860006101000a81548160ff0219169083151502179055506000821461113d5781611140565b60015b600981905550600081146111545780611157565b60015b600a819055505050565b60003073ffffffffffffffffffffffffffffffffffffffff1631905090565b6005806000018054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561121a5780601f106111ef5761010080835404028352916020019161121a565b820191906000526020600020905b8154815290600101906020018083116111fd57829003601f168201915b5050505050908060010154908060020154905083565b60048181548110151561123f57fe5b906000526020600020016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060028054905014156112865760019050611334565b8173ffffffffffffffffffffffffffffffffffffffff166002600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600201548154811015156112ee57fe5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141590505b919050565b6000444260046040518084815260200183815260200182805480156113b357602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611369575b50509350505050604051809103902060019004905090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061140c57805160ff191683800117855561143a565b8280016001018555821561143a579182015b8281111561143957825182559160200191906001019061141e565b5b509050611447919061155c565b5090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061148457805485556114c1565b828001600101855582156114c157600052602060002091601f016020900482015b828111156114c05782548255916001019190600101906114a5565b5b5090506114ce919061155c565b5090565b82805482825590600052602060002090810192821561154b579160200282015b8281111561154a5782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550916020019190600101906114f2565b5b5090506115589190611581565b5090565b61157e91905b8082111561157a576000816000905550600101611562565b5090565b90565b6115c191905b808211156115bd57600081816101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905550600101611587565b5090565b905600a165627a7a72305820a8fb9f06533db9442203332bcb5c2edf68b699d54b7db0be9b1ca78528475c180029 diff --git a/libraries/vendor/xgtvm/lottery2.json b/libraries/vendor/xgtvm/lottery2.json new file mode 100644 index 00000000..8c65486a --- /dev/null +++ b/libraries/vendor/xgtvm/lottery2.json @@ -0,0 +1 @@ +[0x60, 0x80, 0x60, 0x40, 0x52, 0x34, 0x80, 0x15, 0x62, 0x00, 0x00, 0x11, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x60, 0x40, 0x51, 0x62, 0x00, 0x17, 0x54, 0x38, 0x03, 0x80, 0x62, 0x00, 0x17, 0x54, 0x83, 0x39, 0x81, 0x01, 0x80, 0x60, 0x40, 0x52, 0x81, 0x01, 0x90, 0x80, 0x80, 0x51, 0x82, 0x01, 0x92, 0x91, 0x90, 0x60, 0x20, 0x01, 0x80, 0x51, 0x90, 0x60, 0x20, 0x01, 0x90, 0x92, 0x91, 0x90, 0x50, 0x50, 0x50, 0x80, 0x60, 0x01, 0x60, 0x00, 0x61, 0x01, 0x00, 0x0a, 0x81, 0x54, 0x81, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x19, 0x16, 0x90, 0x83, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x02, 0x17, 0x90, 0x55, 0x50, 0x81, 0x60, 0x00, 0x90, 0x80, 0x51, 0x90, 0x60, 0x20, 0x01, 0x90, 0x62, 0x00, 0x00, 0x9c, 0x92, 0x91, 0x90, 0x62, 0x00, 0x00, 0xa5, 0x56, 0x5b, 0x50, 0x50, 0x50, 0x62, 0x00, 0x01, 0x54, 0x56, 0x5b, 0x82, 0x80, 0x54, 0x60, 0x01, 0x81, 0x60, 0x01, 0x16, 0x15, 0x61, 0x01, 0x00, 0x02, 0x03, 0x16, 0x60, 0x02, 0x90, 0x04, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x90, 0x60, 0x1f, 0x01, 0x60, 0x20, 0x90, 0x04, 0x81, 0x01, 0x92, 0x82, 0x60, 0x1f, 0x10, 0x62, 0x00, 0x00, 0xe8, 0x57, 0x80, 0x51, 0x60, 0xff, 0x19, 0x16, 0x83, 0x80, 0x01, 0x17, 0x85, 0x55, 0x62, 0x00, 0x01, 0x19, 0x56, 0x5b, 0x82, 0x80, 0x01, 0x60, 0x01, 0x01, 0x85, 0x55, 0x82, 0x15, 0x62, 0x00, 0x01, 0x19, 0x57, 0x91, 0x82, 0x01, 0x5b, 0x82, 0x81, 0x11, 0x15, 0x62, 0x00, 0x01, 0x18, 0x57, 0x82, 0x51, 0x82, 0x55, 0x91, 0x60, 0x20, 0x01, 0x91, 0x90, 0x60, 0x01, 0x01, 0x90, 0x62, 0x00, 0x00, 0xfb, 0x56, 0x5b, 0x5b, 0x50, 0x90, 0x50, 0x62, 0x00, 0x01, 0x28, 0x91, 0x90, 0x62, 0x00, 0x01, 0x2c, 0x56, 0x5b, 0x50, 0x90, 0x56, 0x5b, 0x62, 0x00, 0x01, 0x51, 0x91, 0x90, 0x5b, 0x80, 0x82, 0x11, 0x15, 0x62, 0x00, 0x01, 0x4d, 0x57, 0x60, 0x00, 0x81, 0x60, 0x00, 0x90, 0x55, 0x50, 0x60, 0x01, 0x01, 0x62, 0x00, 0x01, 0x33, 0x56, 0x5b, 0x50, 0x90, 0x56, 0x5b, 0x90, 0x56, 0x5b, 0x61, 0x15, 0xf0, 0x80, 0x62, 0x00, 0x01, 0x64, 0x60, 0x00, 0x39, 0x60, 0x00, 0xf3, 0x00, 0x60, 0x80, 0x60, 0x40, 0x52, 0x60, 0x04, 0x36, 0x10, 0x61, 0x00, 0xd0, 0x57, 0x60, 0x00, 0x35, 0x7c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x04, 0x63, 0xff, 0xff, 0xff, 0xff, 0x16, 0x80, 0x63, 0x10, 0xc8, 0x5f, 0xe5, 0x14, 0x61, 0x01, 0x10, 0x57, 0x80, 0x63, 0x14, 0x03, 0x4b, 0xd2, 0x14, 0x61, 0x01, 0x3f, 0x57, 0x80, 0x63, 0x1d, 0x27, 0x76, 0x9f, 0x14, 0x61, 0x01, 0x56, 0x57, 0x80, 0x63, 0x23, 0xd1, 0x41, 0x49, 0x14, 0x61, 0x01, 0xb2, 0x57, 0x80, 0x63, 0x48, 0x1c, 0x6a, 0x75, 0x14, 0x61, 0x02, 0x42, 0x57, 0x80, 0x63, 0x58, 0x32, 0xd5, 0x71, 0x14, 0x61, 0x02, 0x99, 0x57, 0x80, 0x63, 0x5c, 0x12, 0xcd, 0x4b, 0x14, 0x61, 0x03, 0x06, 0x57, 0x80, 0x63, 0x5d, 0x58, 0xa7, 0x4a, 0x14, 0x61, 0x03, 0xc9, 0x57, 0x80, 0x63, 0x77, 0x52, 0x04, 0x5b, 0x14, 0x61, 0x03, 0xf4, 0x57, 0x80, 0x63, 0x8b, 0x5b, 0x9c, 0xcc, 0x14, 0x61, 0x04, 0x1f, 0x57, 0x80, 0x63, 0xbd, 0xae, 0xa3, 0x26, 0x14, 0x61, 0x04, 0x8b, 0x57, 0x80, 0x63, 0xd6, 0x88, 0x95, 0xd8, 0x14, 0x61, 0x04, 0xc2, 0x57, 0x80, 0x63, 0xdf, 0xbf, 0x53, 0xae, 0x14, 0x61, 0x04, 0xed, 0x57, 0x80, 0x63, 0xf2, 0x52, 0x66, 0xdd, 0x14, 0x61, 0x05, 0x8b, 0x57, 0x5b, 0x61, 0x01, 0x0e, 0x60, 0x40, 0x80, 0x51, 0x90, 0x81, 0x01, 0x60, 0x40, 0x52, 0x80, 0x60, 0x07, 0x81, 0x52, 0x60, 0x20, 0x01, 0x7f, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x52, 0x50, 0x61, 0x05, 0xf8, 0x56, 0x5b, 0x00, 0x5b, 0x34, 0x80, 0x15, 0x61, 0x01, 0x1c, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x01, 0x25, 0x61, 0x09, 0xee, 0x56, 0x5b, 0x60, 0x40, 0x51, 0x80, 0x82, 0x15, 0x15, 0x15, 0x15, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0xf3, 0x5b, 0x34, 0x80, 0x15, 0x61, 0x01, 0x4b, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x01, 0x54, 0x61, 0x0a, 0x01, 0x56, 0x5b, 0x00, 0x5b, 0x61, 0x01, 0xb0, 0x60, 0x04, 0x80, 0x36, 0x03, 0x81, 0x01, 0x90, 0x80, 0x80, 0x35, 0x90, 0x60, 0x20, 0x01, 0x90, 0x82, 0x01, 0x80, 0x35, 0x90, 0x60, 0x20, 0x01, 0x90, 0x80, 0x80, 0x60, 0x1f, 0x01, 0x60, 0x20, 0x80, 0x91, 0x04, 0x02, 0x60, 0x20, 0x01, 0x60, 0x40, 0x51, 0x90, 0x81, 0x01, 0x60, 0x40, 0x52, 0x80, 0x93, 0x92, 0x91, 0x90, 0x81, 0x81, 0x52, 0x60, 0x20, 0x01, 0x83, 0x83, 0x80, 0x82, 0x84, 0x37, 0x82, 0x01, 0x91, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x91, 0x92, 0x91, 0x92, 0x90, 0x50, 0x50, 0x50, 0x61, 0x05, 0xf8, 0x56, 0x5b, 0x00, 0x5b, 0x34, 0x80, 0x15, 0x61, 0x01, 0xbe, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x01, 0xc7, 0x61, 0x0d, 0xbf, 0x56, 0x5b, 0x60, 0x40, 0x51, 0x80, 0x80, 0x60, 0x20, 0x01, 0x82, 0x81, 0x03, 0x82, 0x52, 0x83, 0x81, 0x81, 0x51, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x80, 0x51, 0x90, 0x60, 0x20, 0x01, 0x90, 0x80, 0x83, 0x83, 0x60, 0x00, 0x5b, 0x83, 0x81, 0x10, 0x15, 0x61, 0x02, 0x07, 0x57, 0x80, 0x82, 0x01, 0x51, 0x81, 0x84, 0x01, 0x52, 0x60, 0x20, 0x81, 0x01, 0x90, 0x50, 0x61, 0x01, 0xec, 0x56, 0x5b, 0x50, 0x50, 0x50, 0x50, 0x90, 0x50, 0x90, 0x81, 0x01, 0x90, 0x60, 0x1f, 0x16, 0x80, 0x15, 0x61, 0x02, 0x34, 0x57, 0x80, 0x82, 0x03, 0x80, 0x51, 0x60, 0x01, 0x83, 0x60, 0x20, 0x03, 0x61, 0x01, 0x00, 0x0a, 0x03, 0x19, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x5b, 0x50, 0x92, 0x50, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0xf3, 0x5b, 0x34, 0x80, 0x15, 0x61, 0x02, 0x4e, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x02, 0x57, 0x61, 0x0e, 0x5d, 0x56, 0x5b, 0x60, 0x40, 0x51, 0x80, 0x82, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0xf3, 0x5b, 0x34, 0x80, 0x15, 0x61, 0x02, 0xa5, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x02, 0xc4, 0x60, 0x04, 0x80, 0x36, 0x03, 0x81, 0x01, 0x90, 0x80, 0x80, 0x35, 0x90, 0x60, 0x20, 0x01, 0x90, 0x92, 0x91, 0x90, 0x50, 0x50, 0x50, 0x61, 0x0e, 0x83, 0x56, 0x5b, 0x60, 0x40, 0x51, 0x80, 0x82, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0xf3, 0x5b, 0x34, 0x80, 0x15, 0x61, 0x03, 0x12, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x03, 0x47, 0x60, 0x04, 0x80, 0x36, 0x03, 0x81, 0x01, 0x90, 0x80, 0x80, 0x35, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x90, 0x60, 0x20, 0x01, 0x90, 0x92, 0x91, 0x90, 0x50, 0x50, 0x50, 0x61, 0x0e, 0xc1, 0x56, 0x5b, 0x60, 0x40, 0x51, 0x80, 0x80, 0x60, 0x20, 0x01, 0x83, 0x81, 0x52, 0x60, 0x20, 0x01, 0x82, 0x81, 0x03, 0x82, 0x52, 0x84, 0x81, 0x81, 0x51, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x80, 0x51, 0x90, 0x60, 0x20, 0x01, 0x90, 0x80, 0x83, 0x83, 0x60, 0x00, 0x5b, 0x83, 0x81, 0x10, 0x15, 0x61, 0x03, 0x8d, 0x57, 0x80, 0x82, 0x01, 0x51, 0x81, 0x84, 0x01, 0x52, 0x60, 0x20, 0x81, 0x01, 0x90, 0x50, 0x61, 0x03, 0x72, 0x56, 0x5b, 0x50, 0x50, 0x50, 0x50, 0x90, 0x50, 0x90, 0x81, 0x01, 0x90, 0x60, 0x1f, 0x16, 0x80, 0x15, 0x61, 0x03, 0xba, 0x57, 0x80, 0x82, 0x03, 0x80, 0x51, 0x60, 0x01, 0x83, 0x60, 0x20, 0x03, 0x61, 0x01, 0x00, 0x0a, 0x03, 0x19, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x5b, 0x50, 0x93, 0x50, 0x50, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0xf3, 0x5b, 0x34, 0x80, 0x15, 0x61, 0x03, 0xd5, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x03, 0xde, 0x61, 0x10, 0x1e, 0x56, 0x5b, 0x60, 0x40, 0x51, 0x80, 0x82, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0xf3, 0x5b, 0x34, 0x80, 0x15, 0x61, 0x04, 0x00, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x04, 0x09, 0x61, 0x10, 0x24, 0x56, 0x5b, 0x60, 0x40, 0x51, 0x80, 0x82, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0xf3, 0x5b, 0x34, 0x80, 0x15, 0x61, 0x04, 0x2b, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x04, 0x34, 0x61, 0x10, 0x2a, 0x56, 0x5b, 0x60, 0x40, 0x51, 0x80, 0x80, 0x60, 0x20, 0x01, 0x82, 0x81, 0x03, 0x82, 0x52, 0x83, 0x81, 0x81, 0x51, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x80, 0x51, 0x90, 0x60, 0x20, 0x01, 0x90, 0x60, 0x20, 0x02, 0x80, 0x83, 0x83, 0x60, 0x00, 0x5b, 0x83, 0x81, 0x10, 0x15, 0x61, 0x04, 0x77, 0x57, 0x80, 0x82, 0x01, 0x51, 0x81, 0x84, 0x01, 0x52, 0x60, 0x20, 0x81, 0x01, 0x90, 0x50, 0x61, 0x04, 0x5c, 0x56, 0x5b, 0x50, 0x50, 0x50, 0x50, 0x90, 0x50, 0x01, 0x92, 0x50, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0xf3, 0x5b, 0x34, 0x80, 0x15, 0x61, 0x04, 0x97, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x04, 0xc0, 0x60, 0x04, 0x80, 0x36, 0x03, 0x81, 0x01, 0x90, 0x80, 0x80, 0x35, 0x90, 0x60, 0x20, 0x01, 0x90, 0x92, 0x91, 0x90, 0x80, 0x35, 0x90, 0x60, 0x20, 0x01, 0x90, 0x92, 0x91, 0x90, 0x50, 0x50, 0x50, 0x61, 0x10, 0xb8, 0x56, 0x5b, 0x00, 0x5b, 0x34, 0x80, 0x15, 0x61, 0x04, 0xce, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x04, 0xd7, 0x61, 0x11, 0x61, 0x56, 0x5b, 0x60, 0x40, 0x51, 0x80, 0x82, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0xf3, 0x5b, 0x34, 0x80, 0x15, 0x61, 0x04, 0xf9, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x05, 0x02, 0x61, 0x11, 0x80, 0x56, 0x5b, 0x60, 0x40, 0x51, 0x80, 0x80, 0x60, 0x20, 0x01, 0x84, 0x81, 0x52, 0x60, 0x20, 0x01, 0x83, 0x81, 0x52, 0x60, 0x20, 0x01, 0x82, 0x81, 0x03, 0x82, 0x52, 0x85, 0x81, 0x81, 0x51, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x80, 0x51, 0x90, 0x60, 0x20, 0x01, 0x90, 0x80, 0x83, 0x83, 0x60, 0x00, 0x5b, 0x83, 0x81, 0x10, 0x15, 0x61, 0x05, 0x4e, 0x57, 0x80, 0x82, 0x01, 0x51, 0x81, 0x84, 0x01, 0x52, 0x60, 0x20, 0x81, 0x01, 0x90, 0x50, 0x61, 0x05, 0x33, 0x56, 0x5b, 0x50, 0x50, 0x50, 0x50, 0x90, 0x50, 0x90, 0x81, 0x01, 0x90, 0x60, 0x1f, 0x16, 0x80, 0x15, 0x61, 0x05, 0x7b, 0x57, 0x80, 0x82, 0x03, 0x80, 0x51, 0x60, 0x01, 0x83, 0x60, 0x20, 0x03, 0x61, 0x01, 0x00, 0x0a, 0x03, 0x19, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x5b, 0x50, 0x94, 0x50, 0x50, 0x50, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0xf3, 0x5b, 0x34, 0x80, 0x15, 0x61, 0x05, 0x97, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x05, 0xb6, 0x60, 0x04, 0x80, 0x36, 0x03, 0x81, 0x01, 0x90, 0x80, 0x80, 0x35, 0x90, 0x60, 0x20, 0x01, 0x90, 0x92, 0x91, 0x90, 0x50, 0x50, 0x50, 0x61, 0x12, 0x30, 0x56, 0x5b, 0x60, 0x40, 0x51, 0x80, 0x82, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0xf3, 0x5b, 0x60, 0x00, 0x81, 0x51, 0x11, 0x15, 0x15, 0x61, 0x06, 0x08, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x60, 0x08, 0x60, 0x00, 0x90, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x60, 0xff, 0x16, 0x15, 0x15, 0x61, 0x06, 0x23, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x67, 0x0d, 0xe0, 0xb6, 0xb3, 0xa7, 0x64, 0x00, 0x00, 0x60, 0x0a, 0x54, 0x02, 0x34, 0x14, 0x15, 0x15, 0x61, 0x06, 0x3d, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x60, 0x09, 0x54, 0x60, 0x03, 0x60, 0x00, 0x33, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x90, 0x81, 0x52, 0x60, 0x20, 0x01, 0x60, 0x00, 0x20, 0x60, 0x01, 0x01, 0x54, 0x10, 0x15, 0x15, 0x61, 0x06, 0x8f, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x61, 0x06, 0x98, 0x33, 0x61, 0x12, 0x6e, 0x56, 0x5b, 0x15, 0x61, 0x07, 0xef, 0x57, 0x60, 0x01, 0x60, 0x03, 0x60, 0x00, 0x33, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x90, 0x81, 0x52, 0x60, 0x20, 0x01, 0x60, 0x00, 0x20, 0x60, 0x01, 0x01, 0x81, 0x90, 0x55, 0x50, 0x80, 0x60, 0x03, 0x60, 0x00, 0x33, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x90, 0x81, 0x52, 0x60, 0x20, 0x01, 0x60, 0x00, 0x20, 0x60, 0x00, 0x01, 0x90, 0x80, 0x51, 0x90, 0x60, 0x20, 0x01, 0x90, 0x61, 0x07, 0x3b, 0x92, 0x91, 0x90, 0x61, 0x13, 0xcb, 0x56, 0x5b, 0x50, 0x60, 0x01, 0x60, 0x02, 0x33, 0x90, 0x80, 0x60, 0x01, 0x81, 0x54, 0x01, 0x80, 0x82, 0x55, 0x80, 0x91, 0x50, 0x50, 0x90, 0x60, 0x01, 0x82, 0x03, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x01, 0x60, 0x00, 0x90, 0x91, 0x92, 0x90, 0x91, 0x90, 0x91, 0x61, 0x01, 0x00, 0x0a, 0x81, 0x54, 0x81, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x19, 0x16, 0x90, 0x83, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x02, 0x17, 0x90, 0x55, 0x50, 0x03, 0x60, 0x03, 0x60, 0x00, 0x33, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x90, 0x81, 0x52, 0x60, 0x20, 0x01, 0x60, 0x00, 0x20, 0x60, 0x02, 0x01, 0x81, 0x90, 0x55, 0x50, 0x61, 0x08, 0x41, 0x56, 0x5b, 0x60, 0x01, 0x60, 0x03, 0x60, 0x00, 0x33, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x90, 0x81, 0x52, 0x60, 0x20, 0x01, 0x60, 0x00, 0x20, 0x60, 0x01, 0x01, 0x60, 0x00, 0x82, 0x82, 0x54, 0x01, 0x92, 0x50, 0x50, 0x81, 0x90, 0x55, 0x50, 0x5b, 0x60, 0x04, 0x33, 0x90, 0x80, 0x60, 0x01, 0x81, 0x54, 0x01, 0x80, 0x82, 0x55, 0x80, 0x91, 0x50, 0x50, 0x90, 0x60, 0x01, 0x82, 0x03, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x01, 0x60, 0x00, 0x90, 0x91, 0x92, 0x90, 0x91, 0x90, 0x91, 0x61, 0x01, 0x00, 0x0a, 0x81, 0x54, 0x81, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x19, 0x16, 0x90, 0x83, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x02, 0x17, 0x90, 0x55, 0x50, 0x50, 0x7f, 0x76, 0x04, 0x1b, 0x6e, 0x81, 0x30, 0x99, 0x58, 0x74, 0xe7, 0x9e, 0x75, 0x1d, 0x28, 0x45, 0x36, 0xc3, 0x72, 0x42, 0xcb, 0x01, 0x4f, 0xb0, 0x58, 0x4e, 0xde, 0x1d, 0x1e, 0x64, 0xce, 0x03, 0xc9, 0x60, 0x03, 0x60, 0x00, 0x33, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x90, 0x81, 0x52, 0x60, 0x20, 0x01, 0x60, 0x00, 0x20, 0x60, 0x00, 0x01, 0x60, 0x03, 0x60, 0x00, 0x33, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x90, 0x81, 0x52, 0x60, 0x20, 0x01, 0x60, 0x00, 0x20, 0x60, 0x01, 0x01, 0x54, 0x60, 0x40, 0x51, 0x80, 0x80, 0x60, 0x20, 0x01, 0x83, 0x81, 0x52, 0x60, 0x20, 0x01, 0x82, 0x81, 0x03, 0x82, 0x52, 0x84, 0x81, 0x81, 0x54, 0x60, 0x01, 0x81, 0x60, 0x01, 0x16, 0x15, 0x61, 0x01, 0x00, 0x02, 0x03, 0x16, 0x60, 0x02, 0x90, 0x04, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x80, 0x54, 0x60, 0x01, 0x81, 0x60, 0x01, 0x16, 0x15, 0x61, 0x01, 0x00, 0x02, 0x03, 0x16, 0x60, 0x02, 0x90, 0x04, 0x80, 0x15, 0x61, 0x09, 0xdc, 0x57, 0x80, 0x60, 0x1f, 0x10, 0x61, 0x09, 0xb1, 0x57, 0x61, 0x01, 0x00, 0x80, 0x83, 0x54, 0x04, 0x02, 0x83, 0x52, 0x91, 0x60, 0x20, 0x01, 0x91, 0x61, 0x09, 0xdc, 0x56, 0x5b, 0x82, 0x01, 0x91, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x90, 0x5b, 0x81, 0x54, 0x81, 0x52, 0x90, 0x60, 0x01, 0x01, 0x90, 0x60, 0x20, 0x01, 0x80, 0x83, 0x11, 0x61, 0x09, 0xbf, 0x57, 0x82, 0x90, 0x03, 0x60, 0x1f, 0x16, 0x82, 0x01, 0x91, 0x5b, 0x50, 0x50, 0x93, 0x50, 0x50, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0xa1, 0x50, 0x56, 0x5b, 0x60, 0x08, 0x60, 0x00, 0x90, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x60, 0xff, 0x16, 0x81, 0x56, 0x5b, 0x60, 0x00, 0x60, 0x01, 0x60, 0x00, 0x90, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x33, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x14, 0x15, 0x15, 0x61, 0x0a, 0x5f, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x60, 0x00, 0x60, 0x04, 0x80, 0x54, 0x90, 0x50, 0x11, 0x15, 0x15, 0x61, 0x0a, 0x73, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x60, 0x04, 0x80, 0x54, 0x90, 0x50, 0x61, 0x0a, 0x81, 0x61, 0x13, 0x39, 0x56, 0x5b, 0x81, 0x15, 0x15, 0x61, 0x0a, 0x8a, 0x57, 0xfe, 0x5b, 0x06, 0x90, 0x50, 0x60, 0x04, 0x81, 0x81, 0x54, 0x81, 0x10, 0x15, 0x15, 0x61, 0x0a, 0x9c, 0x57, 0xfe, 0x5b, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x01, 0x60, 0x00, 0x90, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x61, 0x08, 0xfc, 0x30, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x31, 0x90, 0x81, 0x15, 0x02, 0x90, 0x60, 0x40, 0x51, 0x60, 0x00, 0x60, 0x40, 0x51, 0x80, 0x83, 0x03, 0x81, 0x85, 0x88, 0x88, 0xf1, 0x93, 0x50, 0x50, 0x50, 0x50, 0x15, 0x80, 0x15, 0x61, 0x0b, 0x23, 0x57, 0x3d, 0x60, 0x00, 0x80, 0x3e, 0x3d, 0x60, 0x00, 0xfd, 0x5b, 0x50, 0x60, 0x03, 0x60, 0x00, 0x60, 0x04, 0x83, 0x81, 0x54, 0x81, 0x10, 0x15, 0x15, 0x61, 0x0b, 0x37, 0x57, 0xfe, 0x5b, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x01, 0x60, 0x00, 0x90, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x90, 0x81, 0x52, 0x60, 0x20, 0x01, 0x60, 0x00, 0x20, 0x60, 0x00, 0x01, 0x60, 0x05, 0x60, 0x00, 0x01, 0x90, 0x80, 0x54, 0x60, 0x01, 0x81, 0x60, 0x01, 0x16, 0x15, 0x61, 0x01, 0x00, 0x02, 0x03, 0x16, 0x60, 0x02, 0x90, 0x04, 0x61, 0x0b, 0xc3, 0x92, 0x91, 0x90, 0x61, 0x14, 0x4b, 0x56, 0x5b, 0x50, 0x60, 0x03, 0x60, 0x00, 0x60, 0x04, 0x83, 0x81, 0x54, 0x81, 0x10, 0x15, 0x15, 0x61, 0x0b, 0xd7, 0x57, 0xfe, 0x5b, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x01, 0x60, 0x00, 0x90, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x90, 0x81, 0x52, 0x60, 0x20, 0x01, 0x60, 0x00, 0x20, 0x60, 0x01, 0x01, 0x54, 0x60, 0x05, 0x60, 0x01, 0x01, 0x81, 0x90, 0x55, 0x50, 0x60, 0x00, 0x60, 0x40, 0x51, 0x90, 0x80, 0x82, 0x52, 0x80, 0x60, 0x20, 0x02, 0x60, 0x20, 0x01, 0x82, 0x01, 0x60, 0x40, 0x52, 0x80, 0x15, 0x61, 0x0c, 0x79, 0x57, 0x81, 0x60, 0x20, 0x01, 0x60, 0x20, 0x82, 0x02, 0x80, 0x38, 0x83, 0x39, 0x80, 0x82, 0x01, 0x91, 0x50, 0x50, 0x90, 0x50, 0x5b, 0x50, 0x60, 0x04, 0x90, 0x80, 0x51, 0x90, 0x60, 0x20, 0x01, 0x90, 0x61, 0x0c, 0x8f, 0x92, 0x91, 0x90, 0x61, 0x14, 0xd2, 0x56, 0x5b, 0x50, 0x60, 0x00, 0x60, 0x40, 0x51, 0x90, 0x80, 0x82, 0x52, 0x80, 0x60, 0x20, 0x02, 0x60, 0x20, 0x01, 0x82, 0x01, 0x60, 0x40, 0x52, 0x80, 0x15, 0x61, 0x0c, 0xc0, 0x57, 0x81, 0x60, 0x20, 0x01, 0x60, 0x20, 0x82, 0x02, 0x80, 0x38, 0x83, 0x39, 0x80, 0x82, 0x01, 0x91, 0x50, 0x50, 0x90, 0x50, 0x5b, 0x50, 0x60, 0x02, 0x90, 0x80, 0x51, 0x90, 0x60, 0x20, 0x01, 0x90, 0x61, 0x0c, 0xd6, 0x92, 0x91, 0x90, 0x61, 0x14, 0xd2, 0x56, 0x5b, 0x50, 0x60, 0x00, 0x60, 0x08, 0x60, 0x00, 0x61, 0x01, 0x00, 0x0a, 0x81, 0x54, 0x81, 0x60, 0xff, 0x02, 0x19, 0x16, 0x90, 0x83, 0x15, 0x15, 0x02, 0x17, 0x90, 0x55, 0x50, 0x7f, 0xd6, 0xd1, 0xee, 0xba, 0x63, 0x92, 0x54, 0xbd, 0x05, 0xe3, 0x62, 0x61, 0xae, 0x29, 0x9a, 0xf2, 0x45, 0x32, 0x8a, 0xb9, 0x97, 0xfd, 0x9b, 0x78, 0x23, 0xd5, 0xff, 0xf1, 0x7f, 0x1b, 0x74, 0xa4, 0x60, 0x05, 0x60, 0x00, 0x01, 0x60, 0x05, 0x60, 0x01, 0x01, 0x54, 0x60, 0x40, 0x51, 0x80, 0x80, 0x60, 0x20, 0x01, 0x83, 0x81, 0x52, 0x60, 0x20, 0x01, 0x82, 0x81, 0x03, 0x82, 0x52, 0x84, 0x81, 0x81, 0x54, 0x60, 0x01, 0x81, 0x60, 0x01, 0x16, 0x15, 0x61, 0x01, 0x00, 0x02, 0x03, 0x16, 0x60, 0x02, 0x90, 0x04, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x80, 0x54, 0x60, 0x01, 0x81, 0x60, 0x01, 0x16, 0x15, 0x61, 0x01, 0x00, 0x02, 0x03, 0x16, 0x60, 0x02, 0x90, 0x04, 0x80, 0x15, 0x61, 0x0d, 0xad, 0x57, 0x80, 0x60, 0x1f, 0x10, 0x61, 0x0d, 0x82, 0x57, 0x61, 0x01, 0x00, 0x80, 0x83, 0x54, 0x04, 0x02, 0x83, 0x52, 0x91, 0x60, 0x20, 0x01, 0x91, 0x61, 0x0d, 0xad, 0x56, 0x5b, 0x82, 0x01, 0x91, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x90, 0x5b, 0x81, 0x54, 0x81, 0x52, 0x90, 0x60, 0x01, 0x01, 0x90, 0x60, 0x20, 0x01, 0x80, 0x83, 0x11, 0x61, 0x0d, 0x90, 0x57, 0x82, 0x90, 0x03, 0x60, 0x1f, 0x16, 0x82, 0x01, 0x91, 0x5b, 0x50, 0x50, 0x93, 0x50, 0x50, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0xa1, 0x50, 0x56, 0x5b, 0x60, 0x00, 0x80, 0x54, 0x60, 0x01, 0x81, 0x60, 0x01, 0x16, 0x15, 0x61, 0x01, 0x00, 0x02, 0x03, 0x16, 0x60, 0x02, 0x90, 0x04, 0x80, 0x60, 0x1f, 0x01, 0x60, 0x20, 0x80, 0x91, 0x04, 0x02, 0x60, 0x20, 0x01, 0x60, 0x40, 0x51, 0x90, 0x81, 0x01, 0x60, 0x40, 0x52, 0x80, 0x92, 0x91, 0x90, 0x81, 0x81, 0x52, 0x60, 0x20, 0x01, 0x82, 0x80, 0x54, 0x60, 0x01, 0x81, 0x60, 0x01, 0x16, 0x15, 0x61, 0x01, 0x00, 0x02, 0x03, 0x16, 0x60, 0x02, 0x90, 0x04, 0x80, 0x15, 0x61, 0x0e, 0x55, 0x57, 0x80, 0x60, 0x1f, 0x10, 0x61, 0x0e, 0x2a, 0x57, 0x61, 0x01, 0x00, 0x80, 0x83, 0x54, 0x04, 0x02, 0x83, 0x52, 0x91, 0x60, 0x20, 0x01, 0x91, 0x61, 0x0e, 0x55, 0x56, 0x5b, 0x82, 0x01, 0x91, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x90, 0x5b, 0x81, 0x54, 0x81, 0x52, 0x90, 0x60, 0x01, 0x01, 0x90, 0x60, 0x20, 0x01, 0x80, 0x83, 0x11, 0x61, 0x0e, 0x38, 0x57, 0x82, 0x90, 0x03, 0x60, 0x1f, 0x16, 0x82, 0x01, 0x91, 0x5b, 0x50, 0x50, 0x50, 0x50, 0x50, 0x81, 0x56, 0x5b, 0x60, 0x01, 0x60, 0x00, 0x90, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x56, 0x5b, 0x60, 0x02, 0x81, 0x81, 0x54, 0x81, 0x10, 0x15, 0x15, 0x61, 0x0e, 0x92, 0x57, 0xfe, 0x5b, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x01, 0x60, 0x00, 0x91, 0x50, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x56, 0x5b, 0x60, 0x60, 0x60, 0x00, 0x61, 0x0e, 0xce, 0x83, 0x61, 0x12, 0x6e, 0x56, 0x5b, 0x15, 0x61, 0x0e, 0xf3, 0x57, 0x60, 0x00, 0x60, 0x20, 0x60, 0x40, 0x51, 0x90, 0x81, 0x01, 0x60, 0x40, 0x52, 0x80, 0x60, 0x00, 0x81, 0x52, 0x50, 0x90, 0x80, 0x90, 0x50, 0x91, 0x50, 0x91, 0x50, 0x61, 0x10, 0x19, 0x56, 0x5b, 0x60, 0x03, 0x60, 0x00, 0x84, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x90, 0x81, 0x52, 0x60, 0x20, 0x01, 0x60, 0x00, 0x20, 0x60, 0x00, 0x01, 0x60, 0x03, 0x60, 0x00, 0x85, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x90, 0x81, 0x52, 0x60, 0x20, 0x01, 0x60, 0x00, 0x20, 0x60, 0x01, 0x01, 0x54, 0x81, 0x80, 0x54, 0x60, 0x01, 0x81, 0x60, 0x01, 0x16, 0x15, 0x61, 0x01, 0x00, 0x02, 0x03, 0x16, 0x60, 0x02, 0x90, 0x04, 0x80, 0x60, 0x1f, 0x01, 0x60, 0x20, 0x80, 0x91, 0x04, 0x02, 0x60, 0x20, 0x01, 0x60, 0x40, 0x51, 0x90, 0x81, 0x01, 0x60, 0x40, 0x52, 0x80, 0x92, 0x91, 0x90, 0x81, 0x81, 0x52, 0x60, 0x20, 0x01, 0x82, 0x80, 0x54, 0x60, 0x01, 0x81, 0x60, 0x01, 0x16, 0x15, 0x61, 0x01, 0x00, 0x02, 0x03, 0x16, 0x60, 0x02, 0x90, 0x04, 0x80, 0x15, 0x61, 0x10, 0x0d, 0x57, 0x80, 0x60, 0x1f, 0x10, 0x61, 0x0f, 0xe2, 0x57, 0x61, 0x01, 0x00, 0x80, 0x83, 0x54, 0x04, 0x02, 0x83, 0x52, 0x91, 0x60, 0x20, 0x01, 0x91, 0x61, 0x10, 0x0d, 0x56, 0x5b, 0x82, 0x01, 0x91, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x90, 0x5b, 0x81, 0x54, 0x81, 0x52, 0x90, 0x60, 0x01, 0x01, 0x90, 0x60, 0x20, 0x01, 0x80, 0x83, 0x11, 0x61, 0x0f, 0xf0, 0x57, 0x82, 0x90, 0x03, 0x60, 0x1f, 0x16, 0x82, 0x01, 0x91, 0x5b, 0x50, 0x50, 0x50, 0x50, 0x50, 0x91, 0x50, 0x91, 0x50, 0x91, 0x50, 0x5b, 0x91, 0x50, 0x91, 0x56, 0x5b, 0x60, 0x0a, 0x54, 0x81, 0x56, 0x5b, 0x60, 0x09, 0x54, 0x81, 0x56, 0x5b, 0x60, 0x60, 0x60, 0x02, 0x80, 0x54, 0x80, 0x60, 0x20, 0x02, 0x60, 0x20, 0x01, 0x60, 0x40, 0x51, 0x90, 0x81, 0x01, 0x60, 0x40, 0x52, 0x80, 0x92, 0x91, 0x90, 0x81, 0x81, 0x52, 0x60, 0x20, 0x01, 0x82, 0x80, 0x54, 0x80, 0x15, 0x61, 0x10, 0xae, 0x57, 0x60, 0x20, 0x02, 0x82, 0x01, 0x91, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x90, 0x5b, 0x81, 0x60, 0x00, 0x90, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x90, 0x60, 0x01, 0x01, 0x90, 0x80, 0x83, 0x11, 0x61, 0x10, 0x64, 0x57, 0x5b, 0x50, 0x50, 0x50, 0x50, 0x50, 0x90, 0x50, 0x90, 0x56, 0x5b, 0x60, 0x01, 0x60, 0x00, 0x90, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x33, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x14, 0x15, 0x15, 0x61, 0x11, 0x14, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x60, 0x01, 0x60, 0x08, 0x60, 0x00, 0x61, 0x01, 0x00, 0x0a, 0x81, 0x54, 0x81, 0x60, 0xff, 0x02, 0x19, 0x16, 0x90, 0x83, 0x15, 0x15, 0x02, 0x17, 0x90, 0x55, 0x50, 0x60, 0x00, 0x82, 0x14, 0x61, 0x11, 0x3d, 0x57, 0x81, 0x61, 0x11, 0x40, 0x56, 0x5b, 0x60, 0x01, 0x5b, 0x60, 0x09, 0x81, 0x90, 0x55, 0x50, 0x60, 0x00, 0x81, 0x14, 0x61, 0x11, 0x54, 0x57, 0x80, 0x61, 0x11, 0x57, 0x56, 0x5b, 0x60, 0x01, 0x5b, 0x60, 0x0a, 0x81, 0x90, 0x55, 0x50, 0x50, 0x50, 0x56, 0x5b, 0x60, 0x00, 0x30, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x31, 0x90, 0x50, 0x90, 0x56, 0x5b, 0x60, 0x05, 0x80, 0x60, 0x00, 0x01, 0x80, 0x54, 0x60, 0x01, 0x81, 0x60, 0x01, 0x16, 0x15, 0x61, 0x01, 0x00, 0x02, 0x03, 0x16, 0x60, 0x02, 0x90, 0x04, 0x80, 0x60, 0x1f, 0x01, 0x60, 0x20, 0x80, 0x91, 0x04, 0x02, 0x60, 0x20, 0x01, 0x60, 0x40, 0x51, 0x90, 0x81, 0x01, 0x60, 0x40, 0x52, 0x80, 0x92, 0x91, 0x90, 0x81, 0x81, 0x52, 0x60, 0x20, 0x01, 0x82, 0x80, 0x54, 0x60, 0x01, 0x81, 0x60, 0x01, 0x16, 0x15, 0x61, 0x01, 0x00, 0x02, 0x03, 0x16, 0x60, 0x02, 0x90, 0x04, 0x80, 0x15, 0x61, 0x12, 0x1a, 0x57, 0x80, 0x60, 0x1f, 0x10, 0x61, 0x11, 0xef, 0x57, 0x61, 0x01, 0x00, 0x80, 0x83, 0x54, 0x04, 0x02, 0x83, 0x52, 0x91, 0x60, 0x20, 0x01, 0x91, 0x61, 0x12, 0x1a, 0x56, 0x5b, 0x82, 0x01, 0x91, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x90, 0x5b, 0x81, 0x54, 0x81, 0x52, 0x90, 0x60, 0x01, 0x01, 0x90, 0x60, 0x20, 0x01, 0x80, 0x83, 0x11, 0x61, 0x11, 0xfd, 0x57, 0x82, 0x90, 0x03, 0x60, 0x1f, 0x16, 0x82, 0x01, 0x91, 0x5b, 0x50, 0x50, 0x50, 0x50, 0x50, 0x90, 0x80, 0x60, 0x01, 0x01, 0x54, 0x90, 0x80, 0x60, 0x02, 0x01, 0x54, 0x90, 0x50, 0x83, 0x56, 0x5b, 0x60, 0x04, 0x81, 0x81, 0x54, 0x81, 0x10, 0x15, 0x15, 0x61, 0x12, 0x3f, 0x57, 0xfe, 0x5b, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x01, 0x60, 0x00, 0x91, 0x50, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x56, 0x5b, 0x60, 0x00, 0x80, 0x60, 0x02, 0x80, 0x54, 0x90, 0x50, 0x14, 0x15, 0x61, 0x12, 0x86, 0x57, 0x60, 0x01, 0x90, 0x50, 0x61, 0x13, 0x34, 0x56, 0x5b, 0x81, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x60, 0x02, 0x60, 0x03, 0x60, 0x00, 0x85, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x90, 0x81, 0x52, 0x60, 0x20, 0x01, 0x60, 0x00, 0x20, 0x60, 0x02, 0x01, 0x54, 0x81, 0x54, 0x81, 0x10, 0x15, 0x15, 0x61, 0x12, 0xee, 0x57, 0xfe, 0x5b, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x01, 0x60, 0x00, 0x90, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x14, 0x15, 0x90, 0x50, 0x5b, 0x91, 0x90, 0x50, 0x56, 0x5b, 0x60, 0x00, 0x44, 0x42, 0x60, 0x04, 0x60, 0x40, 0x51, 0x80, 0x84, 0x81, 0x52, 0x60, 0x20, 0x01, 0x83, 0x81, 0x52, 0x60, 0x20, 0x01, 0x82, 0x80, 0x54, 0x80, 0x15, 0x61, 0x13, 0xb3, 0x57, 0x60, 0x20, 0x02, 0x82, 0x01, 0x91, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x90, 0x5b, 0x81, 0x60, 0x00, 0x90, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x90, 0x60, 0x01, 0x01, 0x90, 0x80, 0x83, 0x11, 0x61, 0x13, 0x69, 0x57, 0x5b, 0x50, 0x50, 0x93, 0x50, 0x50, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0x20, 0x60, 0x01, 0x90, 0x04, 0x90, 0x50, 0x90, 0x56, 0x5b, 0x82, 0x80, 0x54, 0x60, 0x01, 0x81, 0x60, 0x01, 0x16, 0x15, 0x61, 0x01, 0x00, 0x02, 0x03, 0x16, 0x60, 0x02, 0x90, 0x04, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x90, 0x60, 0x1f, 0x01, 0x60, 0x20, 0x90, 0x04, 0x81, 0x01, 0x92, 0x82, 0x60, 0x1f, 0x10, 0x61, 0x14, 0x0c, 0x57, 0x80, 0x51, 0x60, 0xff, 0x19, 0x16, 0x83, 0x80, 0x01, 0x17, 0x85, 0x55, 0x61, 0x14, 0x3a, 0x56, 0x5b, 0x82, 0x80, 0x01, 0x60, 0x01, 0x01, 0x85, 0x55, 0x82, 0x15, 0x61, 0x14, 0x3a, 0x57, 0x91, 0x82, 0x01, 0x5b, 0x82, 0x81, 0x11, 0x15, 0x61, 0x14, 0x39, 0x57, 0x82, 0x51, 0x82, 0x55, 0x91, 0x60, 0x20, 0x01, 0x91, 0x90, 0x60, 0x01, 0x01, 0x90, 0x61, 0x14, 0x1e, 0x56, 0x5b, 0x5b, 0x50, 0x90, 0x50, 0x61, 0x14, 0x47, 0x91, 0x90, 0x61, 0x15, 0x5c, 0x56, 0x5b, 0x50, 0x90, 0x56, 0x5b, 0x82, 0x80, 0x54, 0x60, 0x01, 0x81, 0x60, 0x01, 0x16, 0x15, 0x61, 0x01, 0x00, 0x02, 0x03, 0x16, 0x60, 0x02, 0x90, 0x04, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x90, 0x60, 0x1f, 0x01, 0x60, 0x20, 0x90, 0x04, 0x81, 0x01, 0x92, 0x82, 0x60, 0x1f, 0x10, 0x61, 0x14, 0x84, 0x57, 0x80, 0x54, 0x85, 0x55, 0x61, 0x14, 0xc1, 0x56, 0x5b, 0x82, 0x80, 0x01, 0x60, 0x01, 0x01, 0x85, 0x55, 0x82, 0x15, 0x61, 0x14, 0xc1, 0x57, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x91, 0x60, 0x1f, 0x01, 0x60, 0x20, 0x90, 0x04, 0x82, 0x01, 0x5b, 0x82, 0x81, 0x11, 0x15, 0x61, 0x14, 0xc0, 0x57, 0x82, 0x54, 0x82, 0x55, 0x91, 0x60, 0x01, 0x01, 0x91, 0x90, 0x60, 0x01, 0x01, 0x90, 0x61, 0x14, 0xa5, 0x56, 0x5b, 0x5b, 0x50, 0x90, 0x50, 0x61, 0x14, 0xce, 0x91, 0x90, 0x61, 0x15, 0x5c, 0x56, 0x5b, 0x50, 0x90, 0x56, 0x5b, 0x82, 0x80, 0x54, 0x82, 0x82, 0x55, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x90, 0x81, 0x01, 0x92, 0x82, 0x15, 0x61, 0x15, 0x4b, 0x57, 0x91, 0x60, 0x20, 0x02, 0x82, 0x01, 0x5b, 0x82, 0x81, 0x11, 0x15, 0x61, 0x15, 0x4a, 0x57, 0x82, 0x51, 0x82, 0x60, 0x00, 0x61, 0x01, 0x00, 0x0a, 0x81, 0x54, 0x81, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x19, 0x16, 0x90, 0x83, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x02, 0x17, 0x90, 0x55, 0x50, 0x91, 0x60, 0x20, 0x01, 0x91, 0x90, 0x60, 0x01, 0x01, 0x90, 0x61, 0x14, 0xf2, 0x56, 0x5b, 0x5b, 0x50, 0x90, 0x50, 0x61, 0x15, 0x58, 0x91, 0x90, 0x61, 0x15, 0x81, 0x56, 0x5b, 0x50, 0x90, 0x56, 0x5b, 0x61, 0x15, 0x7e, 0x91, 0x90, 0x5b, 0x80, 0x82, 0x11, 0x15, 0x61, 0x15, 0x7a, 0x57, 0x60, 0x00, 0x81, 0x60, 0x00, 0x90, 0x55, 0x50, 0x60, 0x01, 0x01, 0x61, 0x15, 0x62, 0x56, 0x5b, 0x50, 0x90, 0x56, 0x5b, 0x90, 0x56, 0x5b, 0x61, 0x15, 0xc1, 0x91, 0x90, 0x5b, 0x80, 0x82, 0x11, 0x15, 0x61, 0x15, 0xbd, 0x57, 0x60, 0x00, 0x81, 0x81, 0x61, 0x01, 0x00, 0x0a, 0x81, 0x54, 0x90, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x19, 0x16, 0x90, 0x55, 0x50, 0x60, 0x01, 0x01, 0x61, 0x15, 0x87, 0x56, 0x5b, 0x50, 0x90, 0x56, 0x5b, 0x90, 0x56, 0x00, 0xa1, 0x65, 0x62, 0x7a, 0x7a, 0x72, 0x30, 0x58, 0x20, 0xa8, 0xfb, 0x9f, 0x06, 0x53, 0x3d, 0xb9, 0x44, 0x22, 0x03, 0x33, 0x2b, 0xcb, 0x5c, 0x2e, 0xdf, 0x68, 0xb6, 0x99, 0xd5, 0x4b, 0x7d, 0xb0, 0xbe, 0x9b, 0x1c, 0xa7, 0x85, 0x28, 0x47, 0x5c, 0x18, 0x00, 0x29] diff --git a/libraries/vendor/xgtvm/programs/xgtvm.cpp b/libraries/vendor/xgtvm/programs/xgtvm.cpp new file mode 100644 index 00000000..10d13d5a --- /dev/null +++ b/libraries/vendor/xgtvm/programs/xgtvm.cpp @@ -0,0 +1,233 @@ +#include +#include +#include +#include +#include +#include +#include "machine.hpp" +#include "unistd.h" + +std::string process_stdin() +{ + std::cin >> std::noskipws; + std::istream_iterator it(std::cin); + std::istream_iterator end; + std::string results(it, end); + return results; +} + +machine::word to_hex(std::string str) +{ + return std::stoi(str, 0, 16); +} + +std::vector process_eval(const std::string& str) +{ + char delim = ' '; + std::size_t current, previous = 0; + std::string token; + std::vector tokens; + current = str.find(delim); + while (current != std::string::npos) { + tokens.push_back( to_hex( str.substr(previous, current - previous) ) ); + previous = current + 1; + current = str.find(delim, previous); + } + token = str.substr(previous, current - previous); + tokens.push_back( to_hex(token) ); + return tokens; +} + +// Set by --debug or -d +static int debug_flag; +// Set by --eval or -e +static int eval_flag; +static char* eval_cstr; +// Set by --help or -h +static int help_flag; +static struct option long_options[] = { + {"eval", required_argument, 0, 'e'}, + {"debug", no_argument, &debug_flag, 'd'}, + {"help", no_argument, &help_flag, 1}, + {0, 0, 0, 0} +}; + +// chain_adapter is state.host equivalent in evmone +machine::chain_adapter make_chain_adapter() +{ + std::function< machine::big_word(std::vector) > sha3 = [](std::vector memory) -> machine::big_word + { + std::cout << "chain_adapter::sha3" << std::endl; + return machine::big_word(0); + }; + + std::function< machine::big_word(machine::big_word) > get_balance = [](machine::big_word address_ripemd160) -> machine::big_word + { + std::cout << "chain_adapter::get_balance" << std::endl; + return machine::big_word(0); + }; + + std::function< machine::big_word(machine::big_word) > get_code_hash = [](machine::big_word address) -> machine::big_word + { + std::cout << "chain_adapter::get_code_hash" << std::endl; + return machine::big_word(0); + }; + + std::function< machine::big_word(uint64_t) > get_block_hash = [](uint64_t block_num) -> machine::big_word + { + std::cout << "chain_adapter::get_block_hash" << std::endl; + return machine::big_word(0); + }; + + std::function< std::vector(machine::big_word) > get_code_at_addr = [](machine::big_word address) -> std::vector + { + std::cout << "chain_adapter::get_code_at_addr" << std::endl; + return {}; + }; + + std::function< machine::big_word(std::vector, machine::big_word) > contract_create = [](std::vector memory, machine::big_word value) -> machine::big_word + { + std::cout << "chain_adapter::contract_create" << std::endl; + return {}; + }; + + std::function< std::pair< machine::word, std::vector >(machine::big_word, uint64_t, machine::big_word, std::vector) > contract_call = [](machine::big_word address, uint64_t energy, machine::big_word value, std::vector args) -> std::pair< machine::word, std::vector > + { + std::cout << "chain_adapter::contract_call" << std::endl; + return {}; + }; + + std::function< std::pair< machine::word, std::vector >(machine::big_word, uint64_t, machine::big_word, std::vector) > contract_callcode = [](machine::big_word address, uint64_t energy, machine::big_word value, std::vector args) -> std::pair< machine::word, std::vector > + { + std::cout << "chain_adapter::contract_callcode" << std::endl; + return {}; + }; + + std::function< std::pair< machine::word, std::vector >(machine::big_word, uint64_t, std::vector) > contract_delegatecall = [](machine::big_word address, uint64_t energy, std::vector args) -> std::pair< machine::word, std::vector > + { + std::cout << "chain_adapter::contract_delegatecall" << std::endl; + return {}; + }; + + std::function< std::pair< machine::word, std::vector >(machine::big_word, uint64_t, std::vector) > contract_staticcall = [](machine::big_word address, uint64_t energy, std::vector args) -> std::pair< machine::word, std::vector > + { + std::cout << "chain_adapter::contract_staticcall" << std::endl; + return {}; + }; + + std::function< machine::big_word(std::vector, machine::big_word, machine::big_word) > contract_create2 = [](std::vector memory, machine::big_word value, machine::big_word salt) -> machine::big_word + { + std::cout << "chain_adapter::contract_create2" << std::endl; + return {}; + }; + + std::function< bool(std::vector) > revert = [](std::vector memory) -> bool + { + std::cout << "chain_adapter::revert" << std::endl; + return {}; + }; + + std::function< machine::big_word(machine::big_word) > get_storage = [](machine::big_word) -> machine::big_word + { + std::cout << "chain_adapter::get_storage" << std::endl; + + return machine::big_word(0); + }; + + std::function< bool(machine::big_word, machine::big_word) > set_storage = [](machine::big_word, machine::big_word value) -> bool + { + std::cout << "chain_adapter::set_storage" << std::endl; + return false; + }; + + std::function< std::vector(std::vector) > contract_return = [](std::vector memory) -> std::vector + { + std::cout << "chain_adapter::contract_return" << std::endl; + return {}; + }; + + std::function< bool(machine::big_word) > self_destruct = [](machine::big_word address) -> bool + { + std::cout << "chain_adapter::self_destruct" << std::endl; + return {}; + }; + + machine::chain_adapter adapter = { + sha3, + get_balance, + get_code_hash, + get_block_hash, + get_code_at_addr, + contract_create, + contract_call, + contract_callcode, + contract_delegatecall, + contract_staticcall, + contract_create2, + revert, + get_storage, + set_storage, + contract_return, + self_destruct, + }; + + return adapter; +} + +int main(int argc, char** argv) +{ + int c; + for (;;) + { + int option_index = 0; + c = getopt_long(argc, argv, "de:h", long_options, &option_index); + if (c == -1) + break; + switch(c) + { + case 'd': + debug_flag = 1; + break; + case 'e': + eval_flag = 1; + eval_cstr = optarg; + break; + case 'h': + help_flag = 1; + break; + } + } + + // TODO: Add a help message + if (help_flag) + {} + + std::string input = process_stdin(); + if(eval_flag) + input = std::string(eval_cstr); + if (input.size() > 0) + { + machine::context ctx = {true, 0x5c477758}; + machine::message msg = {}; + std::vector code = process_eval(input); + machine::chain_adapter adapter = make_chain_adapter(); + machine::machine m(ctx, code, msg, adapter); + std::string line; + while (m.is_running()) + { + if (debug_flag) + std::cerr << "step\n"; + m.step(); + // Print out any logging that was generated + if (debug_flag) + while ( std::getline(m.get_logger(), line) ) + std::cerr << "\e[36m" << "LOG: " << line << "\e[0m" << std::endl; + } + if (debug_flag) + while ( std::getline(m.get_logger(), line) ) + std::cerr << "\e[36m" << "LOG: " << line << "\e[0m" << std::endl; + std::cout << m.to_json() << std::endl; + } + + return 0; +} diff --git a/libraries/vendor/xgtvm/programs/xgtvm_tests.cpp b/libraries/vendor/xgtvm/programs/xgtvm_tests.cpp new file mode 100644 index 00000000..2fdf80b4 --- /dev/null +++ b/libraries/vendor/xgtvm/programs/xgtvm_tests.cpp @@ -0,0 +1,333 @@ +#include +#include "machine.hpp" + +#define test_that(message) \ + std::cerr << "\e[34m" << ( message ) << "\e[0m" << std::endl; +#define assert_message(message, assertion) \ +{ \ + bool result = ( assertion ); \ + std::cerr << " " << ( result ? "\e[32m" : "\e[31m" ) << ( message ) << "\e[0m" << std::endl; \ +} + +machine::chain_adapter make_chain_adapter() +{ + std::function< machine::big_word(std::vector) > sha3 = [](std::vector memory) -> machine::big_word + { + std::cout << "chain_adapter::sha3" << std::endl; + return machine::big_word(0); + }; + + std::function< machine::big_word(machine::big_word) > get_balance = [](machine::big_word address_ripemd160) -> machine::big_word + { + std::cout << "chain_adapter::get_balance" << std::endl; + return machine::big_word(0); + }; + + std::function< machine::big_word(machine::big_word) > get_code_hash = [](machine::big_word address) -> machine::big_word + { + std::cout << "chain_adapter::get_code_hash" << std::endl; + return machine::big_word(0); + }; + + std::function< machine::big_word(uint64_t) > get_block_hash = [](uint64_t block_num) -> machine::big_word + { + std::cout << "chain_adapter::get_block_hash" << std::endl; + return machine::big_word(0); + }; + + std::function< std::vector(machine::big_word) > get_code_at_addr = [](machine::big_word address) -> std::vector + { + std::cout << "chain_adapter::get_code_at_addr" << std::endl; + return {}; + }; + + std::function< machine::big_word(std::vector, machine::big_word) > contract_create = [](std::vector memory, machine::big_word value) -> machine::big_word + { + std::cout << "chain_adapter::contract_create" << std::endl; + return {}; + }; + + std::function< std::pair< machine::word, std::vector >(machine::big_word, uint64_t, machine::big_word, std::vector) > contract_call = [](machine::big_word address, uint64_t energy, machine::big_word value, std::vector args) -> std::pair< machine::word, std::vector > + { + std::cout << "chain_adapter::contract_call" << std::endl; + return {}; + }; + + std::function< std::pair< machine::word, std::vector >(machine::big_word, uint64_t, machine::big_word, std::vector) > contract_callcode = [](machine::big_word address, uint64_t energy, machine::big_word value, std::vector args) -> std::pair< machine::word, std::vector > + { + std::cout << "chain_adapter::contract_callcode" << std::endl; + return {}; + }; + + std::function< std::pair< machine::word, std::vector >(machine::big_word, uint64_t, std::vector) > contract_delegatecall = [](machine::big_word address, uint64_t energy, std::vector args) -> std::pair< machine::word, std::vector > + { + std::cout << "chain_adapter::contract_delegatecall" << std::endl; + return {}; + }; + + std::function< std::pair< machine::word, std::vector >(machine::big_word, uint64_t, std::vector) > contract_staticcall = [](machine::big_word address, uint64_t energy, std::vector args) -> std::pair< machine::word, std::vector > + { + std::cout << "chain_adapter::contract_staticcall" << std::endl; + return {}; + }; + + std::function< machine::big_word(std::vector, machine::big_word, machine::big_word) > contract_create2 = [](std::vector memory, machine::big_word value, machine::big_word salt) -> machine::big_word + { + std::cout << "chain_adapter::contract_create2" << std::endl; + return {}; + }; + + std::function< bool(std::vector) > revert = [](std::vector memory) -> bool + { + std::cout << "chain_adapter::revert" << std::endl; + return {}; + }; + + std::function< machine::big_word(machine::big_word) > get_storage = [](machine::big_word) -> machine::big_word + { + std::cout << "chain_adapter::get_storage" << std::endl; + + return machine::big_word(0); + }; + + std::function< bool(machine::big_word, machine::big_word) > set_storage = [](machine::big_word, machine::big_word value) -> bool + { + std::cout << "chain_adapter::set_storage" << std::endl; + return false; + }; + + std::function< std::vector(std::vector) > contract_return = [](std::vector memory) -> std::vector + { + std::cout << "chain_adapter::contract_return" << std::endl; + return {}; + }; + + std::function< bool(machine::big_word) > self_destruct = [](machine::big_word address) -> bool + { + std::cout << "chain_adapter::self_destruct" << std::endl; + return {}; + }; + + machine::chain_adapter adapter = { + sha3, + get_balance, + get_code_hash, + get_block_hash, + get_code_at_addr, + contract_create, + contract_call, + contract_callcode, + contract_delegatecall, + contract_staticcall, + contract_create2, + revert, + get_storage, + set_storage, + contract_return, + self_destruct, + }; + + return adapter; +} + +int main(int argc, char** argv) +{ + //test_that("machine runs and halts") + //{ + // std::vector input = {0x00}; + // machine::context ctx = {true, 0x00}; + // machine::message msg = {}; + // machine::chain_adapter adapter = make_chain_adapter(); + // machine::machine m(ctx, input, msg, adapter); + // assert_message( "machine should start running", m.get_state() == machine::machine_state::running ); + // while (m.is_running()) + // m.step(); + // assert_message( "machine should stop when done executing", m.get_state() == machine::machine_state::stopped ); + // assert_message( "stack has correct length", m.stack_length() == 0 ); + //} + + //test_that("machine halts when nothing else to do") + //{ + // std::vector input = {}; + // machine::context ctx = {true, 0x00}; + // machine::message msg = {}; + // machine::chain_adapter adapter = make_chain_adapter(); + // machine::machine m(ctx, input, msg, adapter); + // while (m.is_running()) + // m.step(); + // assert_message( "machine should stop when done executing", m.get_state() == machine::machine_state::stopped ); + // assert_message( "stack has correct length", m.stack_length() == 0 ); + //} + + //test_that("machine returns a timestamp") + //{ + // std::vector input = {0x42, 0x00}; + // machine::context ctx = {true, 0x5c477758}; + // machine::message msg = {}; + // machine::chain_adapter adapter = make_chain_adapter(); + // machine::machine m(ctx, input, msg, adapter); + // while (m.is_running()) + // m.step(); + // assert_message( "machine should stop when done executing", m.get_state() == machine::machine_state::stopped ); + // assert_message( "stack has correct length", m.stack_length() == 1 ); + // assert_message( "top of stack has correct value", m.peek_word() == 0x5c477758 ); + //} + + //test_that("machine adds unsigned 8-bit values") + //{ + // std::vector input = {0x60, 0x02, 0x60, 0x03, 0x01, 0x00}; + // machine::context ctx = {true, 0x00}; + // machine::message msg = {}; + // machine::chain_adapter adapter = make_chain_adapter(); + // machine::machine m(ctx, input, msg, adapter); + // while (m.is_running()) + // m.step(); + // assert_message( "machine should stop when done executing", m.get_state() == machine::machine_state::stopped ); + // assert_message( "stack has correct length", m.stack_length() == 1 ); + // assert_message( "top of stack has correct value", m.peek_word() == 5 ); + //} + + //test_that("machine can store and load a value to/from memory") + //{ + // std::vector input = {0x60, 0x01, 0x60, 0x08, 0x52, 0x60, 0x08, 0x51, 0x00}; + // machine::context ctx = {true, 0x00}; + // machine::message msg = {}; + // machine::chain_adapter adapter = make_chain_adapter(); + // machine::machine m(ctx, input, msg, adapter); + // while (m.is_running()) + // m.step(); + // assert_message( "machine should stop when done executing", m.get_state() == machine::machine_state::stopped ); + // assert_message( "stack has correct length", m.stack_length() == 1 ); + // assert_message( "top of stack has correct value", m.peek_word() == 1 ); + //} + + //test_that("machine can get a wallet's balance via the chain adapter") + //{ + // std::vector input = {0x31, 0x00}; + // machine::context ctx = {true, 0x00}; + // machine::message msg = {}; + // machine::chain_adapter adapter = make_chain_adapter(); + // adapter.get_balance = [](std::string wallet_name) -> uint64_t + // { + // return 2; + // }; + // machine::machine m(ctx, input, msg, adapter); + // m.push_string("alice"); + // while (m.is_running()) + // m.step(); + // assert_message( "machine should stop when done executing", m.get_state() == machine::machine_state::stopped ); + // assert_message( "stack has correct length", m.stack_length() == 1 ); + // assert_message( "top of stack has correct value", m.peek_word() == 2 ); + //} + + // test_that("do nothing contract evaluates") + // { + // std::vector input = {0x60, 0x80, 0x60, 0x40, 0x52, 0x34, 0x80, 0x15, 0x60, 0x0f, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x60, 0x6d, 0x80, 0x60, 0x1d, 0x60, 0x00, 0x39, 0x60, 0x00, 0xf3, 0xfe, 0x60, 0x80, 0x60, 0x40, 0x52, 0x34, 0x80, 0x15, 0x60, 0x0f, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x60, 0x04, 0x36, 0x10, 0x60, 0x28, 0x57, 0x60, 0x00, 0x35, 0x60, 0xe0, 0x1c, 0x80, 0x63, 0x2f, 0x57, 0x6f, 0x20, 0x14, 0x60, 0x2d, 0x57, 0x5b, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x60, 0x33, 0x60, 0x35, 0x56, 0x5b, 0x00, 0x5b, 0x56, 0xfe, 0xa2, 0x64, 0x69, 0x70, 0x66, 0x73, 0x58, 0x22, 0x12, 0x20, 0x97, 0x5b, 0xdb, 0x69, 0x49, 0x44, 0x25, 0x38, 0xb9, 0x0c, 0x14, 0xc4, 0x20, 0xb0, 0xa2, 0xf5, 0x47, 0xf0, 0x43, 0x7e, 0x85, 0xa7, 0x3d, 0xa1, 0x2f, 0xaf, 0x4e, 0x68, 0x34, 0xf0, 0x81, 0x72, 0x64, 0x73, 0x6f, 0x6c, 0x63, 0x43, 0x00, 0x08, 0x07, 0x00, 0x33}; + // machine::context ctx = {true, 0x00}; + // machine::message msg = {}; + // machine::chain_adapter adapter = make_chain_adapter(); + // machine::machine m(ctx, input, msg, adapter); + // assert_message( "machine should start running", m.get_state() == machine::machine_state::running ); + + // auto& logger = m.get_logger(); + // std::string line; + // std::cerr << "\e[36m" << "LOG: " << m.to_json() << "\e[0m" << std::endl; + // while (m.is_running()) + // { + // m.step(); + // //// TODO: Figure out why logs not emitting + // //while ( std::getline(logger, line) ) + // // std::cerr << "\e[36m" << "LOG: " << line << "\e[0m" << std::endl; + // std::cerr << "\e[36m" << "LOG: " << m.to_json() << "\e[0m" << std::endl; + // } + // //while ( std::getline(logger, line) ) + // // std::cerr << "\e[36m" << "LOG: " << line << "\e[0m" << std::endl; + // std::cerr << "\e[36m" << "LOG: " << m.to_json() << "\e[0m" << std::endl; + + // assert_message( "machine should stop when done executing", m.get_state() == machine::machine_state::stopped ); + // assert_message( "stack has correct length", m.stack_length() == 0 ); + // } + + // test_that("storage contract evaluates") + // { + // std::vector input = {0x60, 0x80, 0x60, 0x40, 0x52, 0x34, 0x80, 0x15, 0x61, 0x00, 0x10, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x01, 0x50, 0x80, 0x61, 0x00, 0x20, 0x60, 0x00, 0x39, 0x60, 0x00, 0xf3, 0xfe, 0x60, 0x80, 0x60, 0x40, 0x52, 0x34, 0x80, 0x15, 0x61, 0x00, 0x10, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x60, 0x04, 0x36, 0x10, 0x61, 0x00, 0x36, 0x57, 0x60, 0x00, 0x35, 0x60, 0xe0, 0x1c, 0x80, 0x63, 0x2e, 0x64, 0xce, 0xc1, 0x14, 0x61, 0x00, 0x3b, 0x57, 0x80, 0x63, 0x60, 0x57, 0x36, 0x1d, 0x14, 0x61, 0x00, 0x59, 0x57, 0x5b, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x61, 0x00, 0x43, 0x61, 0x00, 0x75, 0x56, 0x5b, 0x60, 0x40, 0x51, 0x61, 0x00, 0x50, 0x91, 0x90, 0x61, 0x00, 0xd9, 0x56, 0x5b, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0xf3, 0x5b, 0x61, 0x00, 0x73, 0x60, 0x04, 0x80, 0x36, 0x03, 0x81, 0x01, 0x90, 0x61, 0x00, 0x6e, 0x91, 0x90, 0x61, 0x00, 0x9d, 0x56, 0x5b, 0x61, 0x00, 0x7e, 0x56, 0x5b, 0x00, 0x5b, 0x60, 0x00, 0x80, 0x54, 0x90, 0x50, 0x90, 0x56, 0x5b, 0x80, 0x60, 0x00, 0x81, 0x90, 0x55, 0x50, 0x50, 0x56, 0x5b, 0x60, 0x00, 0x81, 0x35, 0x90, 0x50, 0x61, 0x00, 0x97, 0x81, 0x61, 0x01, 0x03, 0x56, 0x5b, 0x92, 0x91, 0x50, 0x50, 0x56, 0x5b, 0x60, 0x00, 0x60, 0x20, 0x82, 0x84, 0x03, 0x12, 0x15, 0x61, 0x00, 0xb3, 0x57, 0x61, 0x00, 0xb2, 0x61, 0x00, 0xfe, 0x56, 0x5b, 0x5b, 0x60, 0x00, 0x61, 0x00, 0xc1, 0x84, 0x82, 0x85, 0x01, 0x61, 0x00, 0x88, 0x56, 0x5b, 0x91, 0x50, 0x50, 0x92, 0x91, 0x50, 0x50, 0x56, 0x5b, 0x61, 0x00, 0xd3, 0x81, 0x61, 0x00, 0xf4, 0x56, 0x5b, 0x82, 0x52, 0x50, 0x50, 0x56, 0x5b, 0x60, 0x00, 0x60, 0x20, 0x82, 0x01, 0x90, 0x50, 0x61, 0x00, 0xee, 0x60, 0x00, 0x83, 0x01, 0x84, 0x61, 0x00, 0xca, 0x56, 0x5b, 0x92, 0x91, 0x50, 0x50, 0x56, 0x5b, 0x60, 0x00, 0x81, 0x90, 0x50, 0x91, 0x90, 0x50, 0x56, 0x5b, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x61, 0x01, 0x0c, 0x81, 0x61, 0x00, 0xf4, 0x56, 0x5b, 0x81, 0x14, 0x61, 0x01, 0x17, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x56, 0xfe, 0xa2, 0x64, 0x69, 0x70, 0x66, 0x73, 0x58, 0x22, 0x12, 0x20, 0x40, 0x4e, 0x37, 0xf4, 0x87, 0xa8, 0x9a, 0x93, 0x2d, 0xca, 0x5e, 0x77, 0xfa, 0xaf, 0x6c, 0xa2, 0xde, 0x3b, 0x99, 0x1f, 0x93, 0xd2, 0x30, 0x60, 0x4b, 0x1b, 0x8d, 0xaa, 0xef, 0x64, 0x76, 0x62, 0x64, 0x73, 0x6f, 0x6c, 0x63, 0x43, 0x00, 0x08, 0x07, 0x00, 0x33}; + // machine::context ctx = {true, 0x00}; + // machine::message msg = {}; + // machine::chain_adapter adapter = make_chain_adapter(); + // machine::machine m(ctx, input, msg, adapter); + // assert_message( "machine should start running", m.get_state() == machine::machine_state::running ); + + // auto& logger = m.get_logger(); + // std::string line; + // std::cerr << "\e[36m" << "LOG: " << m.to_json() << "\e[0m" << std::endl; + // while (m.is_running()) + // { + // m.step(); + // //// TODO: Figure out why logs not emitting + // //while ( std::getline(logger, line) ) + // // std::cerr << "\e[36m" << "LOG: " << line << "\e[0m" << std::endl; + // std::cerr << "\e[36m" << "LOG: " << m.to_json() << "\e[0m" << std::endl; + // } + // //while ( std::getline(logger, line) ) + // // std::cerr << "\e[36m" << "LOG: " << line << "\e[0m" << std::endl; + // std::cerr << "\e[36m" << "LOG: " << m.to_json() << "\e[0m" << std::endl; + + // assert_message( "machine should stop when done executing", m.get_state() == machine::machine_state::stopped ); + // assert_message( "stack has correct length", m.stack_length() == 0 ); + // } + + //test_that("first lottery contract evaluates") + //{ + // std::vector input = {0x60, 0x80, 0x60, 0x40, 0x52, 0x34, 0x80, 0x15, 0x61, 0x00, 0x10, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x33, 0x60, 0x00, 0x80, 0x61, 0x01, 0x00, 0x0a, 0x81, 0x54, 0x81, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x19, 0x16, 0x90, 0x83, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x02, 0x17, 0x90, 0x55, 0x50, 0x61, 0x06, 0x80, 0x80, 0x61, 0x00, 0x60, 0x60, 0x00, 0x39, 0x60, 0x00, 0xf3, 0x00, 0x60, 0x80, 0x60, 0x40, 0x52, 0x60, 0x04, 0x36, 0x10, 0x61, 0x00, 0x6d, 0x57, 0x60, 0x00, 0x35, 0x7c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x04, 0x63, 0xff, 0xff, 0xff, 0xff, 0x16, 0x80, 0x63, 0x48, 0x1c, 0x6a, 0x75, 0x14, 0x61, 0x00, 0x72, 0x57, 0x80, 0x63, 0x5d, 0x49, 0x5a, 0xea, 0x14, 0x61, 0x00, 0xc9, 0x57, 0x80, 0x63, 0x8b, 0x5b, 0x9c, 0xcc, 0x14, 0x61, 0x00, 0xe0, 0x57, 0x80, 0x63, 0xe9, 0x7d, 0xcb, 0x62, 0x14, 0x61, 0x01, 0x4c, 0x57, 0x80, 0x63, 0xf7, 0x1d, 0x96, 0xcb, 0x14, 0x61, 0x01, 0x56, 0x57, 0x5b, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x34, 0x80, 0x15, 0x61, 0x00, 0x7e, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x00, 0x87, 0x61, 0x01, 0xc3, 0x56, 0x5b, 0x60, 0x40, 0x51, 0x80, 0x82, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0xf3, 0x5b, 0x34, 0x80, 0x15, 0x61, 0x00, 0xd5, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x00, 0xde, 0x61, 0x01, 0xe8, 0x56, 0x5b, 0x00, 0x5b, 0x34, 0x80, 0x15, 0x61, 0x00, 0xec, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x00, 0xf5, 0x61, 0x03, 0x40, 0x56, 0x5b, 0x60, 0x40, 0x51, 0x80, 0x80, 0x60, 0x20, 0x01, 0x82, 0x81, 0x03, 0x82, 0x52, 0x83, 0x81, 0x81, 0x51, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x80, 0x51, 0x90, 0x60, 0x20, 0x01, 0x90, 0x60, 0x20, 0x02, 0x80, 0x83, 0x83, 0x60, 0x00, 0x5b, 0x83, 0x81, 0x10, 0x15, 0x61, 0x01, 0x38, 0x57, 0x80, 0x82, 0x01, 0x51, 0x81, 0x84, 0x01, 0x52, 0x60, 0x20, 0x81, 0x01, 0x90, 0x50, 0x61, 0x01, 0x1d, 0x56, 0x5b, 0x50, 0x50, 0x50, 0x50, 0x90, 0x50, 0x01, 0x92, 0x50, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0xf3, 0x5b, 0x61, 0x01, 0x54, 0x61, 0x03, 0xce, 0x56, 0x5b, 0x00, 0x5b, 0x34, 0x80, 0x15, 0x61, 0x01, 0x62, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x50, 0x61, 0x01, 0x81, 0x60, 0x04, 0x80, 0x36, 0x03, 0x81, 0x01, 0x90, 0x80, 0x80, 0x35, 0x90, 0x60, 0x20, 0x01, 0x90, 0x92, 0x91, 0x90, 0x50, 0x50, 0x50, 0x61, 0x04, 0x4b, 0x56, 0x5b, 0x60, 0x40, 0x51, 0x80, 0x82, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x91, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0xf3, 0x5b, 0x60, 0x00, 0x80, 0x90, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x56, 0x5b, 0x60, 0x00, 0x80, 0x60, 0x00, 0x90, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x33, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x14, 0x15, 0x15, 0x61, 0x02, 0x45, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x60, 0x01, 0x80, 0x54, 0x90, 0x50, 0x61, 0x02, 0x53, 0x61, 0x04, 0x89, 0x56, 0x5b, 0x81, 0x15, 0x15, 0x61, 0x02, 0x5c, 0x57, 0xfe, 0x5b, 0x06, 0x90, 0x50, 0x60, 0x01, 0x81, 0x81, 0x54, 0x81, 0x10, 0x15, 0x15, 0x61, 0x02, 0x6e, 0x57, 0xfe, 0x5b, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x01, 0x60, 0x00, 0x90, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x61, 0x08, 0xfc, 0x30, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x31, 0x90, 0x81, 0x15, 0x02, 0x90, 0x60, 0x40, 0x51, 0x60, 0x00, 0x60, 0x40, 0x51, 0x80, 0x83, 0x03, 0x81, 0x85, 0x88, 0x88, 0xf1, 0x93, 0x50, 0x50, 0x50, 0x50, 0x15, 0x80, 0x15, 0x61, 0x02, 0xf5, 0x57, 0x3d, 0x60, 0x00, 0x80, 0x3e, 0x3d, 0x60, 0x00, 0xfd, 0x5b, 0x50, 0x60, 0x00, 0x60, 0x40, 0x51, 0x90, 0x80, 0x82, 0x52, 0x80, 0x60, 0x20, 0x02, 0x60, 0x20, 0x01, 0x82, 0x01, 0x60, 0x40, 0x52, 0x80, 0x15, 0x61, 0x03, 0x26, 0x57, 0x81, 0x60, 0x20, 0x01, 0x60, 0x20, 0x82, 0x02, 0x80, 0x38, 0x83, 0x39, 0x80, 0x82, 0x01, 0x91, 0x50, 0x50, 0x90, 0x50, 0x5b, 0x50, 0x60, 0x01, 0x90, 0x80, 0x51, 0x90, 0x60, 0x20, 0x01, 0x90, 0x61, 0x03, 0x3c, 0x92, 0x91, 0x90, 0x61, 0x05, 0x87, 0x56, 0x5b, 0x50, 0x50, 0x56, 0x5b, 0x60, 0x60, 0x60, 0x01, 0x80, 0x54, 0x80, 0x60, 0x20, 0x02, 0x60, 0x20, 0x01, 0x60, 0x40, 0x51, 0x90, 0x81, 0x01, 0x60, 0x40, 0x52, 0x80, 0x92, 0x91, 0x90, 0x81, 0x81, 0x52, 0x60, 0x20, 0x01, 0x82, 0x80, 0x54, 0x80, 0x15, 0x61, 0x03, 0xc4, 0x57, 0x60, 0x20, 0x02, 0x82, 0x01, 0x91, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x90, 0x5b, 0x81, 0x60, 0x00, 0x90, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x90, 0x60, 0x01, 0x01, 0x90, 0x80, 0x83, 0x11, 0x61, 0x03, 0x7a, 0x57, 0x5b, 0x50, 0x50, 0x50, 0x50, 0x50, 0x90, 0x50, 0x90, 0x56, 0x5b, 0x66, 0x23, 0x86, 0xf2, 0x6f, 0xc1, 0x00, 0x00, 0x34, 0x11, 0x15, 0x15, 0x61, 0x03, 0xe3, 0x57, 0x60, 0x00, 0x80, 0xfd, 0x5b, 0x60, 0x01, 0x33, 0x90, 0x80, 0x60, 0x01, 0x81, 0x54, 0x01, 0x80, 0x82, 0x55, 0x80, 0x91, 0x50, 0x50, 0x90, 0x60, 0x01, 0x82, 0x03, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x01, 0x60, 0x00, 0x90, 0x91, 0x92, 0x90, 0x91, 0x90, 0x91, 0x61, 0x01, 0x00, 0x0a, 0x81, 0x54, 0x81, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x19, 0x16, 0x90, 0x83, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x02, 0x17, 0x90, 0x55, 0x50, 0x50, 0x56, 0x5b, 0x60, 0x01, 0x81, 0x81, 0x54, 0x81, 0x10, 0x15, 0x15, 0x61, 0x04, 0x5a, 0x57, 0xfe, 0x5b, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x01, 0x60, 0x00, 0x91, 0x50, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x56, 0x5b, 0x60, 0x00, 0x44, 0x42, 0x60, 0x01, 0x60, 0x40, 0x51, 0x60, 0x20, 0x01, 0x80, 0x84, 0x81, 0x52, 0x60, 0x20, 0x01, 0x83, 0x81, 0x52, 0x60, 0x20, 0x01, 0x82, 0x80, 0x54, 0x80, 0x15, 0x61, 0x05, 0x06, 0x57, 0x60, 0x20, 0x02, 0x82, 0x01, 0x91, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x90, 0x5b, 0x81, 0x60, 0x00, 0x90, 0x54, 0x90, 0x61, 0x01, 0x00, 0x0a, 0x90, 0x04, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x81, 0x52, 0x60, 0x20, 0x01, 0x90, 0x60, 0x01, 0x01, 0x90, 0x80, 0x83, 0x11, 0x61, 0x04, 0xbc, 0x57, 0x5b, 0x50, 0x50, 0x93, 0x50, 0x50, 0x50, 0x50, 0x60, 0x40, 0x51, 0x60, 0x20, 0x81, 0x83, 0x03, 0x03, 0x81, 0x52, 0x90, 0x60, 0x40, 0x52, 0x60, 0x40, 0x51, 0x80, 0x82, 0x80, 0x51, 0x90, 0x60, 0x20, 0x01, 0x90, 0x80, 0x83, 0x83, 0x5b, 0x60, 0x20, 0x83, 0x10, 0x15, 0x15, 0x61, 0x05, 0x51, 0x57, 0x80, 0x51, 0x82, 0x52, 0x60, 0x20, 0x82, 0x01, 0x91, 0x50, 0x60, 0x20, 0x81, 0x01, 0x90, 0x50, 0x60, 0x20, 0x83, 0x03, 0x92, 0x50, 0x61, 0x05, 0x2c, 0x56, 0x5b, 0x60, 0x01, 0x83, 0x60, 0x20, 0x03, 0x61, 0x01, 0x00, 0x0a, 0x03, 0x80, 0x19, 0x82, 0x51, 0x16, 0x81, 0x84, 0x51, 0x16, 0x80, 0x82, 0x17, 0x85, 0x52, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x90, 0x50, 0x01, 0x91, 0x50, 0x50, 0x60, 0x40, 0x51, 0x80, 0x91, 0x03, 0x90, 0x20, 0x60, 0x01, 0x90, 0x04, 0x90, 0x50, 0x90, 0x56, 0x5b, 0x82, 0x80, 0x54, 0x82, 0x82, 0x55, 0x90, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0x20, 0x90, 0x81, 0x01, 0x92, 0x82, 0x15, 0x61, 0x06, 0x00, 0x57, 0x91, 0x60, 0x20, 0x02, 0x82, 0x01, 0x5b, 0x82, 0x81, 0x11, 0x15, 0x61, 0x05, 0xff, 0x57, 0x82, 0x51, 0x82, 0x60, 0x00, 0x61, 0x01, 0x00, 0x0a, 0x81, 0x54, 0x81, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x19, 0x16, 0x90, 0x83, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0x02, 0x17, 0x90, 0x55, 0x50, 0x91, 0x60, 0x20, 0x01, 0x91, 0x90, 0x60, 0x01, 0x01, 0x90, 0x61, 0x05, 0xa7, 0x56, 0x5b, 0x5b, 0x50, 0x90, 0x50, 0x61, 0x06, 0x0d, 0x91, 0x90, 0x61, 0x06, 0x11, 0x56, 0x5b, 0x50, 0x90, 0x56, 0x5b, 0x61, 0x06, 0x51, 0x91, 0x90, 0x5b, 0x80, 0x82, 0x11, 0x15, 0x61, 0x06, 0x4d, 0x57, 0x60, 0x00, 0x81, 0x81, 0x61, 0x01, 0x00, 0x0a, 0x81, 0x54, 0x90, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x19, 0x16, 0x90, 0x55, 0x50, 0x60, 0x01, 0x01, 0x61, 0x06, 0x17, 0x56, 0x5b, 0x50, 0x90, 0x56, 0x5b, 0x90, 0x56, 0x00, 0xa1, 0x65, 0x62, 0x7a, 0x7a, 0x72, 0x30, 0x58, 0x20, 0x91, 0x9b, 0x1f, 0x32, 0x9a, 0xfa, 0x64, 0x06, 0xac, 0x32, 0xcc, 0xc8, 0x12, 0xf6, 0x5d, 0x08, 0xdc, 0xb2, 0x9f, 0x0c, 0x1b, 0x9f, 0xb6, 0x3c, 0xf3, 0x4e, 0x5a, 0xbf, 0xde, 0xf8, 0xda, 0x07, 0x00, 0x29}; + // machine::context ctx = {true, 0x00}; + // machine::message msg = {}; + // machine::chain_adapter adapter = make_chain_adapter(); + // machine::machine m(ctx, input, msg, adapter); + // assert_message( "machine should start running", m.get_state() == machine::machine_state::running ); + + // std::string line; + // while (m.is_running()) + // { + // m.step(); + // while ( std::getline(m.get_logger(), line) ) + // std::cerr << "\e[36m" << "LOG: " << line << "\e[0m" << std::endl; + // std::cout << m.to_json() << std::endl; + // } + // while ( std::getline(m.get_logger(), line) ) + // std::cerr << "\e[36m" << "LOG: " << line << "\e[0m" << std::endl; + // std::cout << m.to_json() << std::endl; + + // assert_message( "machine should stop when done executing", m.get_state() == machine::machine_state::stopped ); + // assert_message( "stack has correct length", m.stack_length() == 0 ); + //} + + test_that("push opcodes / to_big_word work") + { + std::vector input = {0x7f, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00}; + machine::context ctx = {true, 0x00}; + machine::message msg = {}; + machine::chain_adapter adapter = make_chain_adapter(); + machine::machine m(ctx, input, msg, adapter); + assert_message( "machine should start running", m.get_state() == machine::machine_state::running ); + + std::string line; + while (m.is_running()) + { + m.step(); + while ( std::getline(m.get_logger(), line) ) + std::cerr << "\e[36m" << "LOG: " << line << "\e[0m" << std::endl; + std::cout << m.to_json() << std::endl; + } + while ( std::getline(m.get_logger(), line) ) + std::cerr << "\e[36m" << "LOG: " << line << "\e[0m" << std::endl; + std::cout << m.to_json() << std::endl; + + assert_message( "machine should stop when done executing", m.get_state() == machine::machine_state::stopped ); + assert_message( "stack has correct length", m.stack_length() == 1 ); + } + + return 0; +} diff --git a/programs/xgtd/main.cpp b/programs/xgtd/main.cpp index 05b075cb..1d8d2bbd 100644 --- a/programs/xgtd/main.cpp +++ b/programs/xgtd/main.cpp @@ -10,6 +10,7 @@ // API plugins #include +#include #include #include #include @@ -27,7 +28,6 @@ #include #include #include -#include #include #include @@ -45,9 +45,9 @@ using std::vector; string& version_string() { static string v_str = + "xgt_version: " + fc::string( xgt::utilities::git_revision_description ) + "\n" + "xgt_blockchain_version: " + fc::string( XGT_BLOCKCHAIN_VERSION ) + "\n" + - "xgt_git_revision: " + fc::string( xgt::utilities::git_revision_sha ) + "\n" + - "fc_git_revision: " + fc::string( fc::git_revision_sha ) + "\n"; + "xgt_git_revision: " + fc::string( xgt::utilities::git_revision_sha ) + "\n"; return v_str; } @@ -96,6 +96,7 @@ int main( int argc, char** argv ) // APIs: xgt::plugins::block_api::block_api_plugin, + xgt::plugins::contract::contract_api_plugin, xgt::plugins::chain::chain_api_plugin, xgt::plugins::database_api::database_api_plugin, xgt::plugins::transaction_api::transaction_api_plugin, diff --git a/tasks/contracts.rake b/tasks/contracts.rake new file mode 100644 index 00000000..5028580c --- /dev/null +++ b/tasks/contracts.rake @@ -0,0 +1,424 @@ +require 'digest' + +def transfer_xgt(from, to, amount) + txn = { + 'extensions' => [], + 'operations' => [ + { + 'type' => 'transfer_operation', + 'value' => { + 'amount' => { + 'amount' => amount.to_s, + 'precision' => 8, + 'nai' => '@@000000021' + }, + 'from' => from, + 'to' => to, + 'json_metadata' => '', + 'extensions' => [] + } + } + ] + } + + id = rpc.broadcast_transaction(txn, [wif], chain_id) + (puts 'Waiting...' or sleep 1) until rpc.transaction_ready?(id) +end + +def create_contract!(owner, keys, code, private_key = wif) + txn = { + 'extensions' => [], + 'operations' => [ + { + 'type' => 'contract_create_operation', + 'value' => { + 'owner' => owner, + 'wallet' => keys['wallet_name'], + 'code' => code + } + } + ] + } + signed = Xgt::Ruby::Auth.sign_transaction(rpc, txn, [private_key], chain_id) + $stderr.puts(%(Registering contract... #{signed.to_json})) + response = nil + begin + response = rpc.call('transaction_api.broadcast_transaction', [signed]) + rescue => e + $stderr.puts e + end + $stderr.puts(%(Received response contract... #{response})) +end + +def invoke_contract!(contract_hash, invoker, value, args) + txn = { + 'extensions' => [], + 'operations' => [ + { + 'type' => 'contract_invoke_operation', + 'value' => { + 'contract_hash' => contract_hash, + 'caller' => invoker, + 'value' => value, + 'args' => args + } + } + ] + } + $stderr.puts(%(Signing contract contract... #{txn.to_json})) + signed = Xgt::Ruby::Auth.sign_transaction(rpc, txn, [wif], chain_id) + $stderr.puts(%(Registering contract... #{signed.to_json})) + response = rpc.call('transaction_api.broadcast_transaction', [signed]) + $stderr.puts(%(Received response contract... #{response})) + response +end + +namespace :contracts do + desc 'Create a sample contract' + task :create do + keys = generate_keys + create_wallet!(keys) + # Bytecode explanation: + # + # 60 03 60 04 01 00 + # PUSH 3 PUSH 4 ADD HALT + # + create_contract!(wallet, keys, '600360040100') + + response = rpc.call('contract_api.list_owner_contracts', { 'owner' => wallet }) || {} + p response + contract_hash = response['contracts'].first['contract_hash'] + response = rpc.call('contract_api.get_contract', { 'contract_hash' => contract_hash }) || {} + p response + + invoke_contract!(contract_hash, keys['wallet_name'], 0, '') + end + + desc 'Create a sample contract which calls another' + task :create_and_call do + create_contract = lambda { |code| + keys = generate_keys + create_wallet!(keys) + create_contract!(wallet, keys, code) + + response = rpc.call('contract_api.list_owner_contracts', { 'owner' => wallet }) || {} + p response + contract_hash = response['contracts'].first['contract_hash'] + response = rpc.call('contract_api.get_contract', { 'contract_hash' => contract_hash }) || {} + p response + + [contract_hash, keys] + } + + # Arguments to `call` opcode are: + # + # energy contract_hash value argsOffset argsLength retOffset retLength + # + # Bytecode explanation: + # + # PUSH 0 PUSH 0 RETURN HALT + # 60 00 60 00 F3 00 + # + contract_hash1, keys1 = create_contract.(%(60006000F300)) + # + # Bytecode explanation: + # + # PUSH 0 PUSH #{contract_hash1} 0 0 0 0 0 CALL HALT + # 60 00 60 #{contract_hash1} 60 00 60 00 60 00 60 00 60 00 F1 00 + # + contract_hash2, keys2 = create_contract.(%(600060#{contract_hash1}60006000600060006000F100)) + + invoke_contract!(contract_hash2, keys2['wallet_name'], 0, '') + end + + desc 'Calling a method in another contract' + task :call_method do + %w( + PUSH1 0x4 CALLDATASIZE LT # Is message data size < 4 bytes + PUSH2 0x41 JUMPI PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV PUSH4 0xFFFFFFFF AND DUP1 PUSH4 0x8976762D EQ PUSH2 0x46 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE ISZERO PUSH2 0x51 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x67 PUSH1 0x4 DUP1 DUP1 CALLDATALOAD + ) + end + + desc 'The "Do Nothing" contract' + task :do_nothing do + create_contract = lambda { |code| + keys = generate_keys + create_wallet!(keys) + create_contract!(wallet, keys, code) + + response = rpc.call('contract_api.list_owner_contracts', { 'owner' => wallet }) || {} + p response + contract_hash = response['contracts'].first['contract_hash'] + response = rpc.call('contract_api.get_contract', { 'contract_hash' => contract_hash }) || {} + p response + + [contract_hash, keys] + } + + contract_hash, keys = create_contract.(%(6080604052348015600f57600080fd5b50606d80601d6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80632f576f2014602d575b600080fd5b60336035565b005b56fea2646970667358221220975bdb6949442538b90c14c420b0a2f547f0437e85a73da12faf4e6834f0817264736f6c63430008070033)) + + invoke_contract!(contract_hash, keys['wallet_name'], 0, '') + end + + desc 'Basic contract create contract' + task :basic_create do + + code = '6080604052604051806101a0016040528061017d815260200161021861017d913960009080519060200190610035929190610048565b5034801561004257600080fd5b506100f3565b828054600181600116156101000203166002900490600052602060002090601f01602090048101928261007e57600085556100c5565b82601f1061009757805160ff19168380011785556100c5565b828001600101855582156100c5579182015b828111156100c45782518255916020019190600101906100a9565b5b5090506100d291906100d6565b5090565b5b808211156100ef5760008160009055506001016100d7565b5090565b610116806101026000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063775c300c14602d575b600080fd5b60336035565b005b6000808054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801560c85780601f10609e5761010080835404028352916020019160c8565b820191906000526020600020905b81548152906001019060200180831160ac57829003601f168201915b5050505050905060008151602083016000f09050505056fea26469706673582212207ebdd3e8a24dd18c61ea1cc0033ad3ac21de43f853f03cfeea42954a7d60c12864736f6c63430007060033608060405234801561001057600080fd5b5061015d806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806306fdde031461003b5780637872ab4914610059575b600080fd5b61004361009d565b6040518082815260200191505060405180910390f35b61009b6004803603602081101561006f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506100c5565b005b60007f736d617278000000000000000000000000000000000000000000000000000000905090565b8073ffffffffffffffffffffffffffffffffffffffff1663380c7a676040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561010d57600080fd5b505af1158015610121573d6000803e3d6000fd5b505050505056fea265627a7a72315820fb2fc7a07f0eebf799c680bb1526641d2d905c19393adf340a04e48c9b527de964736f6c634300050c0032' + end + + desc 'Basic lottery contract' + task :basic_lottery do + + def get_wallet(address) + response = rpc.call('database_api.find_wallets', { 'wallets' => [address] }) + response['wallets'].first + end + + code = %(608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506108b5806100606000396000f3fe60806040526004361061004a5760003560e01c8063481c6a751461004f5780635d495aea1461007a5780638b5b9ccc14610091578063e97dcb62146100bc578063f71d96cb146100c6575b600080fd5b34801561005b57600080fd5b50610064610103565b6040516100719190610657565b60405180910390f35b34801561008657600080fd5b5061008f610127565b005b34801561009d57600080fd5b506100a6610283565b6040516100b39190610672565b60405180910390f35b6100c4610311565b005b3480156100d257600080fd5b506100ed60048036038101906100e891906104ba565b610389565b6040516100fa9190610657565b60405180910390f35b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461017f57600080fd5b600060018054905061018f6103c8565b6101999190610785565b9050600181815481106101af576101ae6107e5565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc479081150290604051600060405180830381858888f1935050505015801561021f573d6000803e3d6000fd5b50600067ffffffffffffffff81111561023b5761023a610814565b5b6040519080825280602002602001820160405280156102695781602001602082028036833780820191505090505b506001908051906020019061027f9291906103fe565b5050565b6060600180548060200260200160405190810160405280929190818152602001828054801561030757602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116102bd575b5050505050905090565b662386f26fc10000341161032457600080fd5b6001339080600181540180825580915050600190039060005260206000200160009091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b6001818154811061039957600080fd5b906000526020600020016000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000444260016040516020016103e09392919061061e565b6040516020818303038152906040528051906020012060001c905090565b828054828255906000526020600020908101928215610477579160200282015b828111156104765782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509160200191906001019061041e565b5b5090506104849190610488565b5090565b5b808211156104a1576000816000905550600101610489565b5090565b6000813590506104b481610868565b92915050565b6000602082840312156104d0576104cf610856565b5b60006104de848285016104a5565b91505092915050565b60006104f38383610517565b60208301905092915050565b600061050b8383610535565b60208301905092915050565b61052081610725565b82525050565b61052f81610725565b82525050565b61053e81610725565b82525050565b600061054f826106b9565b61055981856106e9565b935061056483610694565b8060005b8381101561059557815161057c88826104e7565b9750610587836106cf565b925050600181019050610568565b5085935050505092915050565b60006105ad826106c4565b6105b781856106fa565b93506105c2836106a4565b8060005b838110156105fa576105d782610843565b6105e188826104ff565b97506105ec836106dc565b9250506001810190506105c6565b5085935050505092915050565b61061861061382610757565b61077b565b82525050565b600061062a8286610607565b60208201915061063a8285610607565b60208201915061064a82846105a2565b9150819050949350505050565b600060208201905061066c6000830184610526565b92915050565b6000602082019050818103600083015261068c8184610544565b905092915050565b6000819050602082019050919050565b60008190508160005260206000209050919050565b600081519050919050565b600081549050919050565b6000602082019050919050565b6000600182019050919050565b600082825260208201905092915050565b600081905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061073082610737565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600061077461076f8361085b565b610705565b9050919050565b6000819050919050565b600061079082610757565b915061079b83610757565b9250826107ab576107aa6107b6565b5b828206905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600061084f8254610761565b9050919050565b600080fd5b60008160001c9050919050565b61087181610757565b811461087c57600080fd5b5056fea2646970667358221220729e8e8f09800dda1a73c44653546f8c8e4ee6c848019a56bd0d59c47e7aa72564736f6c63430008070033) + + xgt_wallet_0 = 'XGT0000000000000000000000000000000000000000' + + creator_keys = generate_keys + creator = create_wallet!(creator_keys) + transfer_xgt(xgt_wallet_0, creator, 10_000_000) + + alice_keys = generate_keys + alice = create_wallet!(alice_keys) + transfer_xgt(xgt_wallet_0, alice, 20_000_000) + + bob_keys = generate_keys + bob = create_wallet!(bob_keys) + transfer_xgt(xgt_wallet_0, bob, 30_000_000) + + charlie_keys = generate_keys + charlie = create_wallet!(charlie_keys) + transfer_xgt(xgt_wallet_0, charlie, 40_000_000) + + contract_keys = generate_keys + + create_wallet!(contract_keys) + + sleep(2) + + create_contract!(creator, contract_keys, code, creator_keys['recovery_private']) + + sleep(2) + + # Go and get most recently created contract + response = rpc.call('contract_api.list_owner_contracts', { 'owner' => creator }) || {} + p response + contract_hash = response['contracts'].first['contract_hash'] + contract = response['contracts'].first['wallet'] + # Inspect returned contract + # response = rpc.call('contract_api.get_contract', { 'contract_hash' => contract_hash }) || {} + # p response + # + + sleep(2) + + contract_balance_before = get_wallet(contract)['balance']['amount'] + creator_balance_before = get_wallet(creator)['balance']['amount'] + alice_balance_before = get_wallet(alice)['balance']['amount'] + bob_balance_before = get_wallet(bob)['balance']['amount'] + charlie_balance_before = get_wallet(charlie)['balance']['amount'] + + creator_address_r160 = get_wallet(creator)['en_address'] + alice_address_r160 = get_wallet(alice)['en_address'] + bob_address_r160 = get_wallet(bob)['en_address'] + charlie_address_r160 = get_wallet(charlie)['en_address'] + + puts "\n\nCreator address: #{creator}\nRipemd160: #{creator_address_r160}" + puts "\n\nAlice address: #{alice}\nRipemd160: #{alice_address_r160}" + puts "\n\nBob address: #{bob}\nRipemd160: #{bob_address_r160}" + puts "\n\nCharlie address: #{charlie}\nRipemd160: #{charlie_address_r160}\n\n" + + # Creator calls the enter() function + invoke_contract!(contract_hash, creator, 10000000000000001, 'e97dcb62') + sleep(1) + # Alice calls the enter() function + invoke_contract!(contract_hash, alice, 20000000000000002, 'e97dcb62') + sleep(1) + # Bob calls the enter() function + invoke_contract!(contract_hash, bob, 30000000000000003, 'e97dcb62') + sleep(1) + # Charlie calls the enter() function + invoke_contract!(contract_hash, charlie, 40000000000000004, 'e97dcb62') + sleep(1) + # Call the getPlayers() function + invoke_contract!(contract_hash, creator, 0, '8b5b9ccc') + sleep(1) + # Call the pickWinner() function + invoke_contract!(contract_hash, creator, 0, '5d495aea') + + sleep(5) + + contract_balance_after = get_wallet(contract)['balance']['amount'] + creator_balance_after = get_wallet(creator)['balance']['amount'] + alice_balance_after = get_wallet(alice)['balance']['amount'] + bob_balance_after = get_wallet(bob)['balance']['amount'] + charlie_balance_after = get_wallet(charlie)['balance']['amount'] + + puts "\n\nCreator address: #{creator}" + puts "Alice address: #{alice}" + puts "Bob address: #{bob}" + puts "Charlie address: #{charlie}" + + + puts "\n\nContract balance before: #{contract_balance_before}" + puts "\n\nCreator balance before: #{creator_balance_before}" + puts "Alice balance before: #{alice_balance_before}" + puts "Bob balance before: #{bob_balance_before}" + puts "Charlie balance before: #{charlie_balance_before}" + + puts "\n\nContract balance after: #{contract_balance_after}" + puts "\n\nCreator balance after: #{creator_balance_after}" + puts "Alice balance after: #{alice_balance_after}" + puts "Bob balance after: #{bob_balance_after}" + puts "Charlie balance after: #{charlie_balance_after}" + end + + task :test_create do + xgt_wallet_0 = 'XGT0000000000000000000000000000000000000000' + + creator_keys = generate_keys + creator = create_wallet!(creator_keys) + contract_keys = generate_keys + + transfer_xgt(xgt_wallet_0, creator, 20_000_000) + + create_wallet!(contract_keys) + + sleep(2) + + code = %(608060405260046040516100129061008a565b80828152602001915050604051809103906000f080158015610038573d6000803e3d6000fd5b506000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555034801561008457600080fd5b50610096565b60d0806103d683390190565b610331806100a56000396000f3fe6080604052600436106100295760003560e01c80638dcd64cc1461002e57806395fe0e6514610066575b600080fd5b6100646004803603604081101561004457600080fd5b8101908080359060200190929190803590602001909291905050506100a1565b005b34801561007257600080fd5b5061009f6004803603602081101561008957600080fd5b8101908080359060200190929190505050610162565b005b600081836040516100b190610220565b808281526020019150506040518091039082f0801580156100d6573d6000803e3d6000fd5b50905090508073ffffffffffffffffffffffffffffffffffffffff16630c55699c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561012157600080fd5b505afa158015610135573d6000803e3d6000fd5b505050506040513d602081101561014b57600080fd5b810190808051906020019092919050505050505050565b60008160405161017190610220565b80828152602001915050604051809103906000f080158015610197573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff16630c55699c6040518163ffffffff1660e01b815260040160206040518083038186803b1580156101e057600080fd5b505afa1580156101f4573d6000803e3d6000fd5b505050506040513d602081101561020a57600080fd5b8101908080519060200190929190505050505050565b60d08061022d8339019056fe60806040526040516100d03803806100d083398181016040526020811015602557600080fd5b8101908080519060200190929190505050806000819055505060848061004c6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80630c55699c14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea265627a7a723158203e3e89f6c037d9933d5bdef0a2770bf1f37edb6a783aa6541fa6959d9e3dc29364736f6c63430005110032a265627a7a72315820a054097388070f7dcd34b458b35e036d10e3f9defdd31fc4e1d4df5f83232c7564736f6c6343000511003260806040526040516100d03803806100d083398181016040526020811015602557600080fd5b8101908080519060200190929190505050806000819055505060848061004c6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80630c55699c14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea265627a7a723158203e3e89f6c037d9933d5bdef0a2770bf1f37edb6a783aa6541fa6959d9e3dc29364736f6c63430005110032) + stripped_code = %(6080604052600436106100295760003560e01c80638dcd64cc1461002e57806395fe0e6514610066575b600080fd5b6100646004803603604081101561004457600080fd5b8101908080359060200190929190803590602001909291905050506100a1565b005b34801561007257600080fd5b5061009f6004803603602081101561008957600080fd5b8101908080359060200190929190505050610162565b005b600081836040516100b190610220565b808281526020019150506040518091039082f0801580156100d6573d6000803e3d6000fd5b50905090508073ffffffffffffffffffffffffffffffffffffffff16630c55699c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561012157600080fd5b505afa158015610135573d6000803e3d6000fd5b505050506040513d602081101561014b57600080fd5b810190808051906020019092919050505050505050565b60008160405161017190610220565b80828152602001915050604051809103906000f080158015610197573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff16630c55699c6040518163ffffffff1660e01b815260040160206040518083038186803b1580156101e057600080fd5b505afa1580156101f4573d6000803e3d6000fd5b505050506040513d602081101561020a57600080fd5b8101908080519060200190929190505050505050565b60d08061022d8339019056fe60806040526040516100d03803806100d083398181016040526020811015602557600080fd5b8101908080519060200190929190505050806000819055505060848061004c6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80630c55699c14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea265627a7a723158203e3e89f6c037d9933d5bdef0a2770bf1f37edb6a783aa6541fa6959d9e3dc29364736f6c63430005110032a265627a7a72315820a054097388070f7dcd34b458b35e036d10e3f9defdd31fc4e1d4df5f83232c7564736f6c6343000511003260806040526040516100d03803806100d083398181016040526020811015602557600080fd5b8101908080519060200190929190505050806000819055505060848061004c6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80630c55699c14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea265627a7a723158203e3e89f6c037d9933d5bdef0a2770bf1f37edb6a783aa6541fa6959d9e3dc29364736f6c63430005110032) + create_contract!(creator, contract_keys, code, creator_keys['recovery_private']) + + sleep(2) + + response = rpc.call('contract_api.list_owner_contracts', { 'owner' => creator }) || {} + p response + contract_hash = response['contracts'].kind_of?(Array) ? response['contracts'].first['contract_hash'] : response['contracts'].select { |contract| contract['code'] == stripped_code}.first['contract_hash'] + + invoke_contract!(contract_hash, creator, 00000000000000000, '95fe0e650000000000000000000000000000000000000000000000000000000000000001') + + response = rpc.call('contract_api.list_owner_contracts', { 'owner' => creator }) || {} + puts "Creator contracts: \n\n\n" + puts JSON.pretty_generate response + + contract_wallet = response['contracts'].first['wallet'] + + response = rpc.call('contract_api.list_owner_contracts', { 'owner' => contract_wallet }) || {} + puts "Contract contracts: " + puts JSON.pretty_generate response + end + + desc 'Create and execute contract which uses delegatecall opcode' + task :delegatecall do + xgt_wallet_0 = 'XGT0000000000000000000000000000000000000000' + + # Create wallets for each contract + creator_keys = generate_keys + creator = create_wallet!(creator_keys) + + storage_keys = generate_keys + create_wallet!(storage_keys) + + calculator_keys = generate_keys + create_wallet!(calculator_keys) + + machine_keys = generate_keys + create_wallet!(machine_keys) + + sleep(2) + + puts "Wallets created" + + # Create storage contract to be called from machine + storage_code = %(608060405234801561001057600080fd5b5060405161011d38038061011d8339818101604052602081101561003357600080fd5b8101908080519060200190929190505050806000819055505060c38061005a6000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80633c6bb43614603757806355241077146053575b600080fd5b603d607e565b6040518082815260200191505060405180910390f35b607c60048036036020811015606757600080fd5b81019080803590602001909291905050506084565b005b60005481565b806000819055505056fea265627a7a7231582074b793eb6e6838ddcd002ac1df0e6b92009ef3e4437800f9b467f4a9e71251fc64736f6c63430005110032) + create_contract!(creator, storage_keys, storage_code, creator_keys['recovery_private']) + + puts "Created storage contract" + + sleep(2) + + # Create calculator contract to be called using delegatecall from machine + calculator_code = %(608060405234801561001057600080fd5b506101fd806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80634f8632ba146100465780636e008b3514610090578063771602f7146100ae575b600080fd5b61004e6100fa565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610098610120565b6040518082815260200191505060405180910390f35b6100e4600480360360408110156100c457600080fd5b810190808035906020019092919080359060200190929190505050610126565b6040518082815260200191505060405180910390f35b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b600081830160008190555082600054101561013d57fe5b7f7afbe4f1c55b5f72ea356f5b4d5615831867af31454a5ca5557f315e6d11a3698383604051808381526020018281526020019250505060405180910390a133600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060005490509291505056fea265627a7a7231582050376063d00c2b0fa378da9e1c7614c28dfbbaa59458fc67fc68b2d54fed57dd64736f6c63430005110032) + stripped_calculator_code = %(608060405234801561001057600080fd5b50600436106100415760003560e01c80634f8632ba146100465780636e008b3514610090578063771602f7146100ae575b600080fd5b61004e6100fa565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610098610120565b6040518082815260200191505060405180910390f35b6100e4600480360360408110156100c457600080fd5b810190808035906020019092919080359060200190929190505050610126565b6040518082815260200191505060405180910390f35b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b600081830160008190555082600054101561013d57fe5b7f7afbe4f1c55b5f72ea356f5b4d5615831867af31454a5ca5557f315e6d11a3698383604051808381526020018281526020019250505060405180910390a133600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060005490509291505056fea265627a7a7231582050376063d00c2b0fa378da9e1c7614c28dfbbaa59458fc67fc68b2d54fed57dd64736f6c63430005110032) + create_contract!(creator, calculator_keys, calculator_code, creator_keys['recovery_private']) + + puts "Created calculator contract" + + sleep(2) + + # Calling contract aka machine + machine_code = %(608060405234801561001057600080fd5b50600080819055506107d1806100276000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c806386b714e21161005b57806386b714e2146101085780639b7e450c14610152578063c14731ca146101be578063f98f34d8146102045761007d565b806320965255146100825780634f8632ba146100a05780636e008b35146100ea575b600080fd5b61008a610270565b6040518082815260200191505060405180910390f35b6100a861031a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100f2610340565b6040518082815260200191505060405180910390f35b610110610346565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6101a86004803603606081101561016857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919050505061036c565b6040518082815260200191505060405180910390f35b6101ea600480360360208110156101d457600080fd5b8101908080359060200190929190505050610537565b604051808215151515815260200191505060405180910390f35b61025a6004803603606081101561021a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291905050506105cf565b6040518082815260200191505060405180910390f35b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633c6bb4366040518163ffffffff1660e01b815260040160206040518083038186803b1580156102da57600080fd5b505afa1580156102ee573d6000803e3d6000fd5b505050506040513d602081101561030457600080fd5b8101908080519060200190929190505050905090565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060608573ffffffffffffffffffffffffffffffffffffffff16858560405160240180838152602001828152602001925050506040516020818303038152906040527f771602f7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040518082805190602001908083835b60208310610451578051825260208201915060208101905060208303925061042e565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d80600081146104b1576040519150601f19603f3d011682016040523d82523d6000602084013e6104b6565b606091505b50915091507fb3cc7c40ae5fe031ec021a55a5c5cbddcb0837657bfaa8e8249801f67f7296458585846040518084815260200183815260200182151515158152602001935050505060405180910390a180806020019051602081101561051b57600080fd5b8101908080519060200190929190505050925050509392505050565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166355241077836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156105ae57600080fd5b505af11580156105c2573d6000803e3d6000fd5b5050505060019050919050565b60008060608573ffffffffffffffffffffffffffffffffffffffff16858560405160240180838152602001828152602001925050506040516020818303038152906040527f771602f7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040518082805190602001908083835b602083106106b45780518252602082019150602081019050602083039250610691565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114610716576040519150601f19603f3d011682016040523d82523d6000602084013e61071b565b606091505b50915091507f81f50033f40bab548b88ccfd816202734d9325c0718e0395b473afe5454d599e8585846040518084815260200183815260200182151515158152602001935050505060405180910390a180806020019051602081101561078057600080fd5b810190808051906020019092919050505092505050939250505056fea265627a7a72315820a7fa96064b10ab27cbf9ae8932450561f061b789db57f9413d7820936dfcd47b64736f6c63430005110032) + stripped_machine_code = %(608060405234801561001057600080fd5b506004361061007d5760003560e01c806386b714e21161005b57806386b714e2146101085780639b7e450c14610152578063c14731ca146101be578063f98f34d8146102045761007d565b806320965255146100825780634f8632ba146100a05780636e008b35146100ea575b600080fd5b61008a610270565b6040518082815260200191505060405180910390f35b6100a861031a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100f2610340565b6040518082815260200191505060405180910390f35b610110610346565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6101a86004803603606081101561016857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919050505061036c565b6040518082815260200191505060405180910390f35b6101ea600480360360208110156101d457600080fd5b8101908080359060200190929190505050610537565b604051808215151515815260200191505060405180910390f35b61025a6004803603606081101561021a57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291905050506105cf565b6040518082815260200191505060405180910390f35b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633c6bb4366040518163ffffffff1660e01b815260040160206040518083038186803b1580156102da57600080fd5b505afa1580156102ee573d6000803e3d6000fd5b505050506040513d602081101561030457600080fd5b8101908080519060200190929190505050905090565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60005481565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060608573ffffffffffffffffffffffffffffffffffffffff16858560405160240180838152602001828152602001925050506040516020818303038152906040527f771602f7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040518082805190602001908083835b60208310610451578051825260208201915060208101905060208303925061042e565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d80600081146104b1576040519150601f19603f3d011682016040523d82523d6000602084013e6104b6565b606091505b50915091507fb3cc7c40ae5fe031ec021a55a5c5cbddcb0837657bfaa8e8249801f67f7296458585846040518084815260200183815260200182151515158152602001935050505060405180910390a180806020019051602081101561051b57600080fd5b8101908080519060200190929190505050925050509392505050565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166355241077836040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156105ae57600080fd5b505af11580156105c2573d6000803e3d6000fd5b5050505060019050919050565b60008060608573ffffffffffffffffffffffffffffffffffffffff16858560405160240180838152602001828152602001925050506040516020818303038152906040527f771602f7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040518082805190602001908083835b602083106106b45780518252602082019150602081019050602083039250610691565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114610716576040519150601f19603f3d011682016040523d82523d6000602084013e61071b565b606091505b50915091507f81f50033f40bab548b88ccfd816202734d9325c0718e0395b473afe5454d599e8585846040518084815260200183815260200182151515158152602001935050505060405180910390a180806020019051602081101561078057600080fd5b810190808051906020019092919050505092505050939250505056fea265627a7a72315820a7fa96064b10ab27cbf9ae8932450561f061b789db57f9413d7820936dfcd47b64736f6c63430005110032) + create_contract!(creator, machine_keys, machine_code, creator_keys['recovery_private']) + + puts "Created machine contract" + + sleep(2) + + # Refer to https://docs.soliditylang.org/en/develop/abi-spec.html#function-selector-and-argument-encoding + # for rules around argument encoding and calling functions + + # Values to be added together + val1 = "0000000000000000000000000000000000000000000000000000000000000003" + val2 = "0000000000000000000000000000000000000000000000000000000000000004" + + response = rpc.call('contract_api.list_owner_contracts', { 'owner' => creator }) || {} + + puts "\n\n\n\n" + puts machine_keys['wallet_name'] + puts "\n\n\n\n" + puts JSON.pretty_generate response + contract_hash = response['contracts'].first['contract_hash'] + + calculator_contract_address = response['contracts'].select { |contract| contract['code'] == stripped_calculator_code}.first['en_address'] + packed_calculator_contract_address = "000000000000000000000000#{calculator_contract_address}" + + puts "\n\nCalculator contract address: ", calculator_contract_address, "\n" + puts "\nContract args: 9b7e450c#{calculator_contract_address}#{val1}#{val2}\n\n" + + contract_hash = response['contracts'].select { |contract| contract['code'] == stripped_machine_code}.first['contract_hash'] + + # Invoke contract with packed address (2 32-byte words) and args for addValuesWithDelegateCall + invoke_contract!(contract_hash, creator, 0, "9b7e450c#{packed_calculator_contract_address}#{val1}#{val2}") + + puts "Invoked machine contract" + end + + desc 'Create and execute contract which uses create2 opcode' + task :create2 do + # Create wallets for each contract + creator_keys = generate_keys + creator = create_wallet!(creator_keys) + + create2_keys = generate_keys + create2 = create_wallet!(create2_keys) + + sleep(2) + + puts "Wallets created" + + # Create contract to execute create2 + create2_code = %(608060405234801561001057600080fd5b506105c9806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80630bd38f2f14610030575b600080fd5b61004a60048036038101906100459190610181565b61004c565b005b600060ff60f81b3084604051806020016100659061014a565b6020820181038252601f19601f820116604052508560405160200161008b9291906102ab565b604051602081830303815290604052805190602001206040516020016100b4949392919061025d565b6040516020818303038152906040528051906020012060001c9050600083836040516100df9061014a565b6100e991906102d3565b8190604051809103906000f5905080158015610109573d6000803e3d6000fd5b5090508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461014457600080fd5b50505050565b6101688061042c83390190565b600081359050610166816103fd565b92915050565b60008135905061017b81610414565b92915050565b60008060408385031215610198576101976103eb565b5b60006101a685828601610157565b92505060206101b78582860161016c565b9150509250929050565b6101d26101cd82610304565b6103a9565b82525050565b6101e96101e482610316565b6103bb565b82525050565b6102006101fb82610342565b6103c5565b82525050565b6000610211826102ee565b61021b81856102f9565b935061022b818560208601610376565b80840191505092915050565b6102408161036c565b82525050565b6102576102528261036c565b6103e1565b82525050565b600061026982876101d8565b60018201915061027982866101c1565b60148201915061028982856101ef565b60208201915061029982846101ef565b60208201915081905095945050505050565b60006102b78285610206565b91506102c38284610246565b6020820191508190509392505050565b60006020820190506102e86000830184610237565b92915050565b600081519050919050565b600081905092915050565b600061030f8261034c565b9050919050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60005b83811015610394578082015181840152602081019050610379565b838111156103a3576000848401525b50505050565b60006103b4826103cf565b9050919050565b6000819050919050565b6000819050919050565b60006103da826103f0565b9050919050565b6000819050919050565b600080fd5b60008160601b9050919050565b61040681610342565b811461041157600080fd5b50565b61041d8161036c565b811461042857600080fd5b5056fe608060405234801561001057600080fd5b5060405161016838038061016883398181016040528101906100329190610054565b80600081905550506100a7565b60008151905061004e81610090565b92915050565b60006020828403121561006a5761006961008b565b5b60006100788482850161003f565b91505092915050565b6000819050919050565b600080fd5b61009981610081565b81146100a457600080fd5b50565b60b3806100b56000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80630c55699c14602d575b600080fd5b60336047565b604051603e9190605a565b60405180910390f35b60005481565b6054816073565b82525050565b6000602082019050606d6000830184604d565b92915050565b600081905091905056fea2646970667358221220176e7e9577626c01c2b5e46d697777368daa31a61ac6c3fd6cc0bbc5bd4f8f2a64736f6c63430008070033a26469706673582212207eeeb4606f11d013f69f6590f362ffeb0f059f2c641869e03b23a03eb30252f264736f6c63430008070033) + create_contract!(creator, create2_keys, create2_code, creator_keys['recovery_private']) + + puts "Created create2 contract" + + response = rpc.call('contract_api.list_owner_contracts', { 'owner' => creator }) || {} + + stripped_create2_code = %(608060405234801561001057600080fd5b506004361061002b5760003560e01c80630bd38f2f14610030575b600080fd5b61004a60048036038101906100459190610181565b61004c565b005b600060ff60f81b3084604051806020016100659061014a565b6020820181038252601f19601f820116604052508560405160200161008b9291906102ab565b604051602081830303815290604052805190602001206040516020016100b4949392919061025d565b6040516020818303038152906040528051906020012060001c9050600083836040516100df9061014a565b6100e991906102d3565b8190604051809103906000f5905080158015610109573d6000803e3d6000fd5b5090508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461014457600080fd5b50505050565b6101688061042c83390190565b600081359050610166816103fd565b92915050565b60008135905061017b81610414565b92915050565b60008060408385031215610198576101976103eb565b5b60006101a685828601610157565b92505060206101b78582860161016c565b9150509250929050565b6101d26101cd82610304565b6103a9565b82525050565b6101e96101e482610316565b6103bb565b82525050565b6102006101fb82610342565b6103c5565b82525050565b6000610211826102ee565b61021b81856102f9565b935061022b818560208601610376565b80840191505092915050565b6102408161036c565b82525050565b6102576102528261036c565b6103e1565b82525050565b600061026982876101d8565b60018201915061027982866101c1565b60148201915061028982856101ef565b60208201915061029982846101ef565b60208201915081905095945050505050565b60006102b78285610206565b91506102c38284610246565b6020820191508190509392505050565b60006020820190506102e86000830184610237565b92915050565b600081519050919050565b600081905092915050565b600061030f8261034c565b9050919050565b60007fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60005b83811015610394578082015181840152602081019050610379565b838111156103a3576000848401525b50505050565b60006103b4826103cf565b9050919050565b6000819050919050565b6000819050919050565b60006103da826103f0565b9050919050565b6000819050919050565b600080fd5b60008160601b9050919050565b61040681610342565b811461041157600080fd5b50565b61041d8161036c565b811461042857600080fd5b5056fe608060405234801561001057600080fd5b5060405161016838038061016883398181016040528101906100329190610054565b80600081905550506100a7565b60008151905061004e81610090565b92915050565b60006020828403121561006a5761006961008b565b5b60006100788482850161003f565b91505092915050565b6000819050919050565b600080fd5b61009981610081565b81146100a457600080fd5b50565b60b3806100b56000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80630c55699c14602d575b600080fd5b60336047565b604051603e9190605a565b60405180910390f35b60005481565b6054816073565b82525050565b6000602082019050606d6000830184604d565b92915050565b600081905091905056fea2646970667358221220176e7e9577626c01c2b5e46d697777368daa31a61ac6c3fd6cc0bbc5bd4f8f2a64736f6c63430008070033a26469706673582212207eeeb4606f11d013f69f6590f362ffeb0f059f2c641869e03b23a03eb30252f264736f6c63430008070033) + contract_hash = response['contracts'].select { |contract| contract['code'] == stripped_create2_code}.first['contract_hash'] + salt = "1a40000000000000000000000000000000000000000000000000000000000045" + arg1 = "000000000000000000000000000000000000000000000000000000000000002d" + invoke_contract!(contract_hash, creator_keys['wallet_name'], 0, "0bd38f2f#{salt}#{arg1}") + + response = rpc.call('contract_api.list_owner_contracts', { 'owner' => create2 }) || {} + + puts "response" + puts response + end +end diff --git a/tasks/lazy_wallets.rake b/tasks/lazy_wallets.rake new file mode 100644 index 00000000..015ee696 --- /dev/null +++ b/tasks/lazy_wallets.rake @@ -0,0 +1,70 @@ +namespace :lazy_wallets do + task :name_test do + master = Xgt::Ruby::Auth.random_wif + private_key = Xgt::Ruby::Auth.generate_wif(wallet, master, 'recovery') + public_key = Xgt::Ruby::Auth.wif_to_public_key(private_key, address_prefix) + + response = rpc.call('wallet_by_key_api.generate_wallet_name', { + 'recovery_keys' => [public_key] + }) + wallet_name = response['wallet_name'] + + txn = { + 'extensions' => [], + 'operations' => [ + { + 'type' => 'transfer_operation', + 'value' => { + 'amount' => { + 'amount' => '1', + 'precision' => 8, + 'nai' => '@@000000021' + }, + 'from' => 'XGT0000000000000000000000000000000000000000', + 'to' => wallet_name, + 'json_metadata' => '', + 'extensions' => [] + } + } + ] + } + + id = rpc.broadcast_transaction(txn, [wif], chain_id) + (puts 'Waiting...' or sleep 1) until rpc.transaction_ready?(id) + + keys = generate_keys + txn = { + 'extensions' => [], + 'operations' => [ + { + 'type' => 'wallet_update_operation', + 'value' => { + 'wallet' => wallet_name, + 'recovery' => { + 'weight_threshold' => 1, + 'account_auths' => [], + 'key_auths' => [[keys['recovery_public'], 1]] + }, + 'money' => { + 'weight_threshold' => 1, + 'account_auths' => [], + 'key_auths' => [[keys['money_public'], 1]] + }, + 'social' => { + 'weight_threshold' => 1, + 'account_auths' => [], + 'key_auths' => [[keys['social_public'], 1]] + }, + 'memo_key' => keys['memo_public'], + 'json_metadata' => '', + 'extensions' => [] + } + } + ] + } + + p txn + id = rpc.broadcast_transaction(txn, [private_key], chain_id) + (puts 'Waiting...' or sleep 1) until rpc.transaction_ready?(id) + end +end diff --git a/todo.rb b/todo.rb deleted file mode 100644 index 86ca6b82..00000000 --- a/todo.rb +++ /dev/null @@ -1 +0,0 @@ -# 1. tests/tests/block_tests.cpp