npm i -g create-elm-app
您正在查看: 2018年6月
'elm-app' is not recognized as an internal or external command
'elm-install' is not recognized as an internal or external command
npm:
npm install elm-github-install -g
If you are experiencing EACCES: permission denied errors during installation using NPM then you can try:
sudo npm i -g elm-github-install --unsafe-perm=true --allow-root
EOS智能合约产生随机数
先基本记录下,稍后整理,测试,总结
1. How can I generate random numbers inside a smart contract?
if( !is_zero(prev_reveal.reveal) ) {
checksum256 result;
sha256( (char *)&game_itr->player1, sizeof(player)*2, &result);
auto prev_revealer_offer = idx.find( offer::get_commitment(prev_reveal.commitment) );
int winner = result.hash[1] < result.hash[0] ? 0 : 1;
if( winner ) {
pay_and_clean(*game_itr, *curr_revealer_offer, *prev_revealer_offer);
} else {
pay_and_clean(*game_itr, *prev_revealer_offer, *curr_revealer_offer);
}
}
2. EOSDACRandom
#include "eosdacrandom.hpp"
#include <eosiolib/system.h>
#include <eosiolib/stdlib.hpp>
#include <eosiolib/action.hpp>
#include <eosiolib/symbol.hpp>
#include "../eosdactoken/eosdactoken.hpp"
using namespace eosio;
eosdacrandom::eosdacrandom(account_name name)
: contract(name),
_seeds(_self, name),
_geters(_self, name)
{
}
eosdacrandom::~eosdacrandom()
{
}
void eosdacrandom::setsize(uint64_t size)
{
require_auth(_self);
seedconfig_table config(_self, _self);
auto existing = config.find(_self);
if (existing != config.end()) {
if (existing->hash_count == existing->target_size) {
if (existing->hash_count != existing->seed_match) {
eosio_assert(false, "do not set size during sendseed period");
}
}
config.modify(existing, _self, [&](auto& c){
c.target_size = size;
});
} else {
config.emplace(_self, [&](auto& c){
c.owner = _self;
c.target_size = size;
});
}
}
void eosdacrandom::sendseed(name owner, int64_t seed, string sym)
{
eosio_assert(is_account(owner), "Invalid account");
symbol_type symbol(string_to_symbol(4, sym.c_str()));
eosio::asset fromBalance = eosdactoken(N(eosdactoken)).get_balance(owner, symbol.name());
eosio_assert(fromBalance.amount > 0, "account has not enough OCT to do it");
eosio::asset selfBalance = eosdactoken(N(eosdactoken)).get_balance(_self, symbol.name());
eosio_assert(selfBalance.amount > 0, "contract account has not enough OCT to do it");
require_auth(owner);
seedconfig_table config(_self, _self);
auto existing = config.find(_self);
eosio_assert(existing != config.end(), "target size must set first");
const auto& cfg = *existing;
const auto& sd = _seeds.find(owner);
if (cfg.hash_count < cfg.target_size) {
if (sd != _seeds.end()) {
_seeds.erase(sd);
config.modify(cfg, _self, [&](auto& c){
c.hash_count --;
});
}
eosio_assert(false, "hash size not fulled");
}
string h = cal_sha256_str(seed);
eosio_assert(sd->seed != seed, "you have already send seed");
if (sd->hash != h) {
//SEND_INLINE_ACTION( eosdacvote, vote, {_self,N(active)}, {_self, owner, selfBalance, false} );
for (auto itr = _seeds.cbegin(); itr != _seeds.cend(); ) {
itr = _seeds.erase(itr);
}
config.modify(cfg, _self, [&](auto& c){
c.hash_count = 0;
});
return;
}
_seeds.modify(sd, _self, [&](auto& a){
a.seed = seed;
});
config.modify(cfg, _self, [&](auto& c){
c.seed_match = c.seed_match + 1;
print(c.seed_match);
});
// if all seeds match
if (seedsmatch()) {
dispatch_request(owner);
}
}
void eosdacrandom::sendhash(name owner, string hash, string sym)
{
eosio_assert(is_account(owner), "Invalid account");
seedconfig_table config(_self, _self);
auto existing = config.find(_self);
eosio_assert(existing != config.end(), "target size must set first");
const auto& cfg = *existing;
eosio_assert(cfg.hash_count < cfg.target_size, "seeds is full");
symbol_type symbol(string_to_symbol(4, sym.c_str()));
eosio::asset fromBalance = eosdactoken(N(eosdactoken)).get_balance(owner, symbol.name());
eosio_assert(fromBalance.amount > 0, "account has not enough OCT to do it");
require_auth(owner);
auto s = _seeds.find(owner);
if (s == _seeds.end()) {
_seeds.emplace(_self, [&](auto& a){
a.owner = owner;
a.hash = hash;
});
config.modify(cfg, _self, [&](auto& c){
c.hash_count++;
});
} else {
_seeds.modify(s, _self, [&](auto& a){
a.hash = hash;
});
}
}
void eosdacrandom::regrequest(name owner, uint64_t index)
{
eosio_assert(is_account(owner), "Invalid account");
uint64_t cur = current_time();
auto it = _geters.find(owner);
request_info req {index, cur};
if (it == _geters.end()) {
_geters.emplace(_self, [&](auto& a){
a.owner = owner;
a.requestinfo.push_back(req);
});
} else {
_geters.modify(it, _self, [&](auto& a){
bool same_idx = false;
for (auto ri = a.requestinfo.begin(); ri != a.requestinfo.end(); ++ri) {
if (ri->index == index) { // if index equals former index.
*ri = req;
same_idx = true;
break;
}
}
if (!same_idx) {
a.requestinfo.push_back(req);
}
});
}
}
int64_t eosdacrandom::random()
{
// use _seeds to generate random number
seedconfig_table config(_self, _self);
auto existing = config.find(_self);
eosio_assert(existing != config.end(), "target size must set first");
eosio_assert(existing->hash_count == existing->target_size, "seed is not full");
// how to generate random number?
int64_t seed = 0;
for (auto it = _seeds.cbegin(); it != _seeds.cend();) {
seed += it->seed;
it = _seeds.erase(it);
}
config.modify(existing, _self, [&](auto& c){
c.hash_count = 0;
c.seed_match = 0;
});
checksum256 cs = cal_sha256(seed);
return (((int64_t)cs.hash[0] << 56 ) & 0xFF00000000000000U)
| (((int64_t)cs.hash[1] << 48 ) & 0x00FF000000000000U)
| (((int64_t)cs.hash[2] << 40 ) & 0x0000FF0000000000U)
| (((int64_t)cs.hash[3] << 32 ) & 0x000000FF00000000U)
| ((cs.hash[4] << 24 ) & 0x00000000FF000000U)
| ((cs.hash[5] << 16 ) & 0x0000000000FF0000U)
| ((cs.hash[6] << 8 ) & 0x000000000000FF00U)
| (cs.hash[7] & 0x00000000000000FFU);
}
bool eosdacrandom::seedsmatch()
{
seedconfig_table config(_self, _self);
auto existing = config.find(_self);
eosio_assert(existing != config.end(), "target size must set first");
const auto& cfg = *existing;
if (cfg.hash_count != cfg.target_size) {
return false;
}
if (cfg.hash_count == cfg.seed_match) {
return true;
}
return false;
}
checksum256 eosdacrandom::cal_sha256(int64_t word)
{
checksum256 cs = { 0 };
char d[255] = { 0 };
snprintf(d, sizeof(d) - 1, "%lld", word);
sha256(d, strlen(d), &cs);
return cs;
}
string eosdacrandom::cal_sha256_str(int64_t word)
{
string h;
checksum256 cs = cal_sha256(word);
for (int i = 0; i < sizeof(cs.hash); ++i) {
char hex[3] = { 0 };
snprintf(hex, sizeof(hex), "%02x", static_cast<unsigned char>(cs.hash[i]));
h += hex;
}
return h;
}
void eosdacrandom::dispatch_request(name owner)
{
print("all seeds matched.");
uint64_t cur = current_time();
int64_t num = random();
static int expiraion = 3000; // ms
std::vector<std::vector<request_info>> reqs;
for (auto i = _geters.cbegin(); i != _geters.cend();) {
std:vector<request_info> tmp(i->requestinfo);
for (auto j = tmp.begin(); j != tmp.end();) {
if (cur - j->timestamp >= expiraion) {
dispatch_inline(i->owner, string_to_name("getrandom"),
{permission_level(_self, N(active))},
std::make_tuple(j->index, num));
j = tmp.erase(j);
} else {
++j;
}
}
if (tmp.size()) {
reqs.push_back(tmp);
}
i = _geters.erase(i);
}
if (reqs.size()) {
for (auto r = reqs.cbegin(); r != reqs.cend(); ++r) {
_geters.emplace(_self, [&](auto& a){
a.owner = owner;
a.requestinfo = *r;
});
}
}
}
EOSIO_ABI( eosdacrandom, (setsize) (sendseed) (sendhash) (regrequest) )
3. eoscraper
#include "scraper.hpp"
#include <set>
#include <map>
#include <vector>
#include "Proof.hh"
#include "Ecc.hh"
//count of participants for random generation (min 4)
constexpr static uint8_t participant_cnt = 10;
static const UInt256 seed_for_g = fromString("21343453542133456453212");
static const UInt256 seed_for_m = fromString("56987654354236234435425");
static const Point base_point { Secp256k1, Secp256k1.G.x, Secp256k1.G.y };
static const Point gen_g = base_point.scalarMult(seed_for_g);
static const Point gen_m = base_point.scalarMult(seed_for_m);
struct binuint256_t {
checksum256 data;
};
struct binpoint {
binuint256_t x, y;
};
struct binproof {
binpoint g,m,h,z,a,b;
binuint256_t c, r;
};
UInt256 fromBin(binuint256_t const & data) {
UInt256 x;
memcpy(x.data, data.data.hash, sizeof(data.data));
return std::move(x);
}
Point fromBin(binpoint const &data) {
Point point {Secp256k1, fromBin(data.x), fromBin(data.y)};
eosio_assert(point.isOnCurve(), "Point not in curve");
return std::move(point);
}
Proof fromBin(binproof const &data) {
return {
fromBin(data.g), fromBin(data.m),
fromBin(data.h), fromBin(data.z),
fromBin(data.a), fromBin(data.b),
fromBin(data.c), fromBin(data.r)
};
}
// @abi table
struct encshare {
uint64_t id;
account_name from;
account_name to;
binpoint data;
binpoint commitment;
binproof proof;
uint64_t dec_id;
auto primary_key() const { return id; }
EOSLIB_SERIALIZE(encshare, (id)(from)(to)(data)(commitment)(proof)(dec_id));
};
// @abi table
struct decshare {
uint64_t id;
binpoint s;
binproof proof;
auto primary_key() const { return id; }
EOSLIB_SERIALIZE(decshare, (id)(s)(proof));
};
// @abi table
struct random {
enum state : uint8_t {
wait_joins = 0,
wait_enc_shares,
wait_dec_shares,
done,
error,
};
uint64_t id;
uint8_t state;
uint8_t joined_cnt;
std::vector<account_name> participants;
uint32_t pushed_cnt;
std::vector<uint64_t> enc_ids;
std::vector<uint8_t> dec_cnts;
auto primary_key()const { return id; }
EOSLIB_SERIALIZE(random, (id)(state)(participants)(enc_ids)(dec_cnts));
};
// @abi table
struct account {
account_name owner;
binpoint pubkey;
auto primary_key()const { return owner; }
EOSLIB_SERIALIZE(account, (owner)(pubkey));
};
class scraper : public eosio::contract {
public:
scraper( account_name self ) :
contract(self),
_accounts(_self, _self),
_randoms( _self, _self),
_encshares(_self, _self),
_decshares(_self, _self)
{ }
// @abi action
void bindkey(account_name sender, binpoint pubkey) {
require_auth(sender);
auto acc = _accounts.find(sender);
if (acc != _accounts.end())
_accounts.modify(acc, sender, [&] (auto & acc) {
acc.pubkey = pubkey;
});
else
_accounts.emplace(sender, [&](auto & acc) {
acc.owner = sender;
acc.pubkey = pubkey;
});
}
// @abi action
void initrand(account_name sender) {
require_auth(sender);
auto acc = _accounts.find(sender);
eosio_assert(acc != _accounts.end(), "Need to bind public key");
_randoms.emplace(sender, [&](auto & rand) {
rand.id = _randoms.available_primary_key();
rand.state = random::state::wait_joins;
rand.participants.reserve(participant_cnt);
rand.enc_ids.reserve(participant_cnt*participant_cnt);
rand.dec_cnts.reserve(participant_cnt);
rand.participants[0] = sender;
rand.joined_cnt = 1;
rand.pushed_cnt = 0;
for(auto k = 0; k < participant_cnt * participant_cnt; ++k)
rand.enc_ids[k] = -1;
});
}
// @abi action
void joinrand(uint64_t rand_id, account_name sender) {
require_auth(sender);
auto acc = _accounts.find(sender);
eosio_assert(acc != _accounts.end(), "Need to bind public key");
auto rand_it = _randoms.find(rand_id);
eosio_assert(rand_it != _randoms.end(), "Rand not found");
eosio_assert(participantId(*rand_it, sender) != -1, "Already joinded");
eosio_assert(rand_it->state == random::state::wait_joins, "Invalid state");
_randoms.modify(rand_it, sender, [&](auto & rand) {
rand.participants[rand.joined_cnt++] = sender;
if (rand.joined_cnt == participant_cnt)
rand.state = random::state::wait_enc_shares;
});
}
// @abi action
void pushencshare(uint64_t rand_id, account_name sender, account_name receiver,
binpoint data, binpoint commitment, binproof proof)
{
require_auth(sender);
auto senderAccIt = _accounts.find(sender);
eosio_assert(senderAccIt != _accounts.end(), "Sender not found");
auto receiverAccIt = _accounts.find(receiver);
eosio_assert(receiverAccIt != _accounts.end(), "Receiver not found");
auto rand_it = _randoms.find(rand_id);
eosio_assert(rand_it != _randoms.end(), "Rand not found");
auto senderPartId = participantId(*rand_it, sender);
eosio_assert(senderPartId != -1, "Sender is not participant");
auto receiverPartId = participantId(*rand_it, receiver);
eosio_assert(receiverPartId != -1, "Receiver is not participant");
eosio_assert(rand_it->enc_ids[(uint32_t)senderPartId * participant_cnt + receiverPartId] == -1, "share already pushed");
auto pk = fromBin(receiverAccIt->pubkey);
auto pr = fromBin(proof);
eosio_assert(gen_g == pr.g, "Invalid proof (gen_g != g)");
eosio_assert(pk == pr.m, "Invalid proof (pk != m)");
eosio_assert(pr.verify(), "Proof validate failed");
uint64_t new_share_id;
_encshares.emplace(sender, [&](auto & share) {
new_share_id = _encshares.available_primary_key();
share.id = new_share_id;
share.from = sender;
share.to = receiver;
share.data = data;
share.commitment = commitment;
share.proof = proof;
share.dec_id = (uint64_t)-1;
});
_randoms.modify(rand_it, sender, [&](auto & rand) {
rand.enc_ids[(uint32_t)senderPartId * participant_cnt + receiverPartId] = new_share_id;
rand.pushed_cnt++;
if (rand.pushed_cnt == (uint32_t)participant_cnt * participant_cnt)
rand.state = random::state::wait_dec_shares;
});
}
// @abi action
void pushdecshare(uint64_t rand_id, account_name sender, account_name from,
binpoint s, binproof proof)
{
require_auth(sender);
auto senderAccIt = _accounts.find(sender);
eosio_assert(senderAccIt != _accounts.end(), "Sender not found");
auto fromAccIt = _accounts.find(from);
eosio_assert(fromAccIt != _accounts.end(), "From not found");
auto rand_it = _randoms.find(rand_id);
eosio_assert(rand_it != _randoms.end(), "Rand not found");
eosio_assert(rand_it->state == random::state::wait_dec_shares, "Invalid state");
auto senderPartId = participantId(*rand_it, from);
eosio_assert(senderPartId != -1, "Sender is not participant");
auto receiverPartId = participantId(*rand_it, sender);
eosio_assert(receiverPartId != -1, "Receiver is not participant");
auto enc_id = rand_it->enc_ids[(uint32_t)senderPartId * participant_cnt + receiverPartId];
auto encshare_it = _encshares.find(enc_id);
eosio_assert(encshare_it != _encshares.end(), "Share not found");
eosio_assert(encshare_it->dec_id == -1, "Already pushed");
auto encdata = fromBin(encshare_it->data);
auto pk = fromBin(senderAccIt->pubkey);
auto ss = fromBin(s);
auto pr = fromBin(proof);
eosio_assert(gen_g == pr.g, "Invalid proof (gen_g != g)");
eosio_assert(encdata == pr.z, "Invalid proof (encdata != g)");
eosio_assert(ss == pr.m, "Invalid proof (m != s)");
eosio_assert(pk == pr.h, "Invalid proof (pk != h)");
eosio_assert(pr.verify(), "Proof validate failed");
uint64_t new_dec_id;
_decshares.emplace(sender, [&](auto & obj) {
new_dec_id = _decshares.available_primary_key();
obj.id = new_dec_id;
obj.s = s;
obj.proof = proof;
});
_encshares.modify(encshare_it, sender, [&](auto & obj) {
obj.dec_id = new_dec_id;
});
_randoms.modify(rand_it, sender, [&](auto & rand) {
rand.dec_cnts[from]++;
});
}
private:
eosio::multi_index<N(accounts), account> _accounts;
eosio::multi_index<N(randoms), random> _randoms;
eosio::multi_index<N(encshare), encshare> _encshares;
eosio::multi_index<N(decshare), decshare> _decshares;
private:
uint8_t participantId(random const & obj, account_name acc) {
for (uint8_t i = 0; i < participant_cnt; ++i)
if (obj.participants[i] == acc)
return i;
return -1;
}
};
EOSIO_ABI( scraper, (bindkey)(initrand)(joinrand)(pushencshare)(pushdecshare))
最新回复
Cindy: 你好,前面都跑下来了,想问一下在最后一步显示的访问网址...
surou: https://eosnodes.privex.io/
surou: 有问题可以加社群,沟通更及时 社区QQ群:79142...
surou: 再仔细确认下输入吧,错误是说 交易体不符合JSON,
pp: hello,我用cleos -u http://127...
surou: https://validate.eosnation....
surou: https://validate.eosnation....
surou: https://validate.eosnation....
surou: https://snapshots.eosamster...
weimumu: https://eosnode.tools/好像没有提...
归档
January 2021December 2020November 2020October 2020September 2020July 2020June 2020May 2020April 2020March 2020February 2020January 2020December 2019November 2019October 2019September 2019August 2019July 2019June 2019May 2019April 2019March 2019February 2019January 2019December 2018November 2018October 2018September 2018August 2018July 2018June 2018