DERO-HE STARGATE Testnet Release39
This commit is contained in:
parent
9f67daeb86
commit
9202d01b75
@ -24,12 +24,17 @@
|
||||
- Few more ideas implemented and will be tested for review in upcoming technology preview.
|
||||
-
|
||||
|
||||
|
||||
|
||||
###3.4
|
||||
|
||||
- DAG/MINIDAG with blocks flowing every second
|
||||
- Mining Decentralization.No more mining pools, daily 100000 reward blocks, no need for pools and thus no attacks
|
||||
- Erasure coded blocks, lower bandwidth requirements, very low propagation time. Tested with upto 20 MB blocks.
|
||||
- DERO Simulator for faster Development cycle
|
||||
- Gas Support implemented ( both storage gas/compute gas)
|
||||
- Implemented gas estimation
|
||||
- DVM simulator to test all edge cases for SC dev, see dvm/simulator_test.go to see it in action for lotter SC.
|
||||
|
||||
###3.3
|
||||
|
||||
|
@ -45,6 +45,7 @@ import "github.com/deroproject/derohe/cryptography/crypto"
|
||||
import "github.com/deroproject/derohe/errormsg"
|
||||
import "github.com/deroproject/derohe/metrics"
|
||||
|
||||
import "github.com/deroproject/derohe/dvm"
|
||||
import "github.com/deroproject/derohe/block"
|
||||
import "github.com/deroproject/derohe/globals"
|
||||
import "github.com/deroproject/derohe/transaction"
|
||||
@ -901,12 +902,12 @@ func (chain *Blockchain) Add_Complete_Block(cbl *block.Complete_Block) (err erro
|
||||
|
||||
// at this point, we must commit all the SCs, so entire tree hash is interlinked
|
||||
for scid, v := range sc_change_cache {
|
||||
meta_bytes, err := sc_meta.Get(SC_Meta_Key(scid))
|
||||
meta_bytes, err := sc_meta.Get(dvm.SC_Meta_Key(scid))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var meta SC_META_DATA // the meta contains metadata about SC
|
||||
var meta dvm.SC_META_DATA // the meta contains metadata about SC
|
||||
if err := meta.UnmarshalBinary(meta_bytes); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -915,7 +916,7 @@ func (chain *Blockchain) Add_Complete_Block(cbl *block.Complete_Block) (err erro
|
||||
panic(err)
|
||||
}
|
||||
|
||||
sc_meta.Put(SC_Meta_Key(scid), meta.MarshalBinary())
|
||||
sc_meta.Put(dvm.SC_Meta_Key(scid), meta.MarshalBinary())
|
||||
data_trees = append(data_trees, v)
|
||||
|
||||
/*fmt.Printf("will commit tree name %x \n", v.GetName())
|
||||
@ -1163,6 +1164,14 @@ func (chain *Blockchain) Add_TX_To_Pool(tx *transaction.Transaction) error {
|
||||
return fmt.Errorf("TX %s rejected Already mined in some block", txhash)
|
||||
}
|
||||
|
||||
toporecord, err := chain.Store.Topo_store.Read(int64(tx.Height))
|
||||
if err != nil {
|
||||
return fmt.Errorf("TX %s rejected height(%d) reference not found", txhash, tx.Height)
|
||||
}
|
||||
if toporecord.BLOCK_ID != tx.BLID {
|
||||
return fmt.Errorf("TX %s rejected block (%s) reference not found", txhash, tx.BLID)
|
||||
}
|
||||
|
||||
hf_version := chain.Get_Current_Version_at_Height(int64(chain_height))
|
||||
|
||||
// if TX is too big, then it cannot be mined due to fixed block size, reject such TXs here
|
||||
|
@ -74,31 +74,31 @@ func (chain *Blockchain) install_hardcoded_contracts(cache map[crypto.Hash]*grav
|
||||
|
||||
// hard coded contracts generally do not do any initialization
|
||||
func (chain *Blockchain) install_hardcoded_sc(cache map[crypto.Hash]*graviton.Tree, ss *graviton.Snapshot, balance_tree *graviton.Tree, sc_tree *graviton.Tree, source string, scid crypto.Hash) (err error) {
|
||||
w_sc_tree := &Tree_Wrapper{tree: sc_tree, entries: map[string][]byte{}}
|
||||
var w_sc_data_tree *Tree_Wrapper
|
||||
w_sc_tree := &dvm.Tree_Wrapper{Tree: sc_tree, Entries: map[string][]byte{}}
|
||||
var w_sc_data_tree *dvm.Tree_Wrapper
|
||||
|
||||
meta := SC_META_DATA{}
|
||||
w_sc_data_tree = wrapped_tree(cache, ss, scid)
|
||||
meta := dvm.SC_META_DATA{}
|
||||
w_sc_data_tree = dvm.Wrapped_tree(cache, ss, scid)
|
||||
|
||||
// install SC, should we check for sanity now, why or why not
|
||||
w_sc_data_tree.Put(SC_Code_Key(scid), dvm.Variable{Type: dvm.String, ValueString: source}.MarshalBinaryPanic())
|
||||
w_sc_tree.Put(SC_Meta_Key(scid), meta.MarshalBinary())
|
||||
w_sc_data_tree.Put(dvm.SC_Code_Key(scid), dvm.Variable{Type: dvm.String, ValueString: source}.MarshalBinaryPanic())
|
||||
w_sc_tree.Put(dvm.SC_Meta_Key(scid), meta.MarshalBinary())
|
||||
|
||||
// we must commit all the changes
|
||||
|
||||
// anything below should never give error
|
||||
if _, ok := cache[scid]; !ok {
|
||||
cache[scid] = w_sc_data_tree.tree
|
||||
cache[scid] = w_sc_data_tree.Tree
|
||||
}
|
||||
|
||||
for k, v := range w_sc_data_tree.entries { // commit entire data to tree
|
||||
if err = w_sc_data_tree.tree.Put([]byte(k), v); err != nil {
|
||||
for k, v := range w_sc_data_tree.Entries { // commit entire data to tree
|
||||
if err = w_sc_data_tree.Tree.Put([]byte(k), v); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range w_sc_tree.entries {
|
||||
if err = w_sc_tree.tree.Put([]byte(k), v); err != nil {
|
||||
for k, v := range w_sc_tree.Entries {
|
||||
if err = w_sc_tree.Tree.Put([]byte(k), v); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ func (pool *Mempool) HouseKeeping(height uint64) {
|
||||
pool.txs.Range(func(k, value interface{}) bool {
|
||||
txhash := k.(crypto.Hash)
|
||||
v := value.(*mempool_object)
|
||||
if height >= (v.Tx.Height) { // if we have moved 10 heights, chances of reorg are almost nil
|
||||
if height >= (v.Tx.Height) { // remove all txs
|
||||
delete_list = append(delete_list, txhash)
|
||||
}
|
||||
return true
|
||||
|
@ -24,7 +24,6 @@ import "strings"
|
||||
import "strconv"
|
||||
import "runtime/debug"
|
||||
import "encoding/hex"
|
||||
import "encoding/binary"
|
||||
import "math/big"
|
||||
import "golang.org/x/xerrors"
|
||||
|
||||
@ -243,38 +242,6 @@ func (chain *Blockchain) process_transaction(changed map[crypto.Hash]*graviton.T
|
||||
}
|
||||
}
|
||||
|
||||
type Tree_Wrapper struct {
|
||||
tree *graviton.Tree
|
||||
entries map[string][]byte
|
||||
transfere []dvm.TransferExternal
|
||||
}
|
||||
|
||||
func (t *Tree_Wrapper) Get(key []byte) ([]byte, error) {
|
||||
if value, ok := t.entries[string(key)]; ok {
|
||||
return value, nil
|
||||
} else {
|
||||
return t.tree.Get(key)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tree_Wrapper) Put(key []byte, value []byte) error {
|
||||
t.entries[string(key)] = append([]byte{}, value...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// checks cache and returns a wrapped tree if possible
|
||||
func wrapped_tree(cache map[crypto.Hash]*graviton.Tree, ss *graviton.Snapshot, id crypto.Hash) *Tree_Wrapper {
|
||||
if cached_tree, ok := cache[id]; ok { // tree is in cache return it
|
||||
return &Tree_Wrapper{tree: cached_tree, entries: map[string][]byte{}}
|
||||
}
|
||||
|
||||
if tree, err := ss.GetTree(string(id[:])); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
return &Tree_Wrapper{tree: tree, entries: map[string][]byte{}}
|
||||
}
|
||||
}
|
||||
|
||||
// does additional processing for SC
|
||||
// all processing occurs in wrapped trees, if any error occurs we dicard all trees
|
||||
func (chain *Blockchain) process_transaction_sc(cache map[crypto.Hash]*graviton.Tree, ss *graviton.Snapshot, bl_height, bl_topoheight, bl_timestamp uint64, blid crypto.Hash, tx transaction.Transaction, balance_tree *graviton.Tree, sc_tree *graviton.Tree) (gas uint64, err error) {
|
||||
@ -285,11 +252,13 @@ func (chain *Blockchain) process_transaction_sc(cache map[crypto.Hash]*graviton.
|
||||
|
||||
gas = tx.Fees()
|
||||
|
||||
w_balance_tree := &Tree_Wrapper{tree: balance_tree, entries: map[string][]byte{}}
|
||||
w_sc_tree := &Tree_Wrapper{tree: sc_tree, entries: map[string][]byte{}}
|
||||
var gascompute, gasstorage uint64
|
||||
|
||||
_ = w_balance_tree
|
||||
var w_sc_data_tree *Tree_Wrapper
|
||||
_ = gascompute
|
||||
_ = gasstorage
|
||||
|
||||
w_sc_tree := &dvm.Tree_Wrapper{Tree: sc_tree, Entries: map[string][]byte{}}
|
||||
var w_sc_data_tree *dvm.Tree_Wrapper
|
||||
|
||||
txhash := tx.GetHash()
|
||||
scid := txhash
|
||||
@ -302,10 +271,22 @@ func (chain *Blockchain) process_transaction_sc(cache map[crypto.Hash]*graviton.
|
||||
}()
|
||||
|
||||
if !tx.SCDATA.Has(rpc.SCACTION, rpc.DataUint64) { // tx doesn't have sc action
|
||||
//err = fmt.Errorf("no scid provided")
|
||||
return tx.Fees(), nil
|
||||
}
|
||||
|
||||
incoming_value := map[crypto.Hash]uint64{}
|
||||
for _, payload := range tx.Payloads {
|
||||
incoming_value[payload.SCID] = payload.BurnValue
|
||||
}
|
||||
|
||||
chain.Expand_Transaction_NonCoinbase(&tx)
|
||||
|
||||
signer, err := Extract_signer(&tx)
|
||||
if err != nil { // allow anonymous SC transactions with condition that SC will not call Signer
|
||||
// this allows anonymous voting and numerous other applications
|
||||
// otherwise SC receives signer as all zeroes
|
||||
}
|
||||
|
||||
action_code := rpc.SC_ACTION(tx.SCDATA.Value(rpc.SCACTION, rpc.DataUint64).(uint64))
|
||||
|
||||
switch action_code {
|
||||
@ -329,21 +310,28 @@ func (chain *Blockchain) process_transaction_sc(cache map[crypto.Hash]*graviton.
|
||||
break
|
||||
}
|
||||
|
||||
meta := SC_META_DATA{}
|
||||
meta := dvm.SC_META_DATA{}
|
||||
if _, ok := sc.Functions["InitializePrivate"]; ok {
|
||||
meta.Type = 1
|
||||
}
|
||||
|
||||
w_sc_data_tree = wrapped_tree(cache, ss, scid)
|
||||
w_sc_data_tree = dvm.Wrapped_tree(cache, ss, scid)
|
||||
|
||||
// install SC, should we check for sanity now, why or why not
|
||||
w_sc_data_tree.Put(SC_Code_Key(scid), dvm.Variable{Type: dvm.String, ValueString: sc_code}.MarshalBinaryPanic())
|
||||
w_sc_tree.Put(SC_Meta_Key(scid), meta.MarshalBinary())
|
||||
w_sc_data_tree.Put(dvm.SC_Code_Key(scid), dvm.Variable{Type: dvm.String, ValueString: sc_code}.MarshalBinaryPanic())
|
||||
w_sc_tree.Put(dvm.SC_Meta_Key(scid), meta.MarshalBinary())
|
||||
|
||||
entrypoint := "Initialize"
|
||||
if meta.Type == 1 { // if its a a private SC
|
||||
gas, err = chain.execute_sc_function(w_sc_tree, w_sc_data_tree, scid, bl_height, bl_topoheight, bl_timestamp, blid, tx, "InitializePrivate", 1)
|
||||
entrypoint = "InitializePrivate"
|
||||
}
|
||||
|
||||
balance, sc_parsed, found := dvm.ReadSC(w_sc_tree, w_sc_data_tree, scid)
|
||||
if found {
|
||||
gascompute, gasstorage, err = dvm.Execute_sc_function(w_sc_tree, w_sc_data_tree, scid, bl_height, bl_topoheight, bl_timestamp, blid, txhash, sc_parsed, entrypoint, 1, balance, signer, incoming_value, tx.SCDATA, tx.Fees(), chain.simulator)
|
||||
} else {
|
||||
gas, err = chain.execute_sc_function(w_sc_tree, w_sc_data_tree, scid, bl_height, bl_topoheight, bl_timestamp, blid, tx, "Initialize", 1)
|
||||
logger.V(1).Error(nil, "SC not found", "scid", scid)
|
||||
err = fmt.Errorf("SC not found %s", scid)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@ -364,17 +352,23 @@ func (chain *Blockchain) process_transaction_sc(cache map[crypto.Hash]*graviton.
|
||||
|
||||
scid = tx.SCDATA.Value(rpc.SCID, rpc.DataHash).(crypto.Hash)
|
||||
|
||||
if _, err = w_sc_tree.Get(SC_Meta_Key(scid)); err != nil {
|
||||
if _, err = w_sc_tree.Get(dvm.SC_Meta_Key(scid)); err != nil {
|
||||
err = fmt.Errorf("scid %s not installed", scid)
|
||||
return
|
||||
}
|
||||
|
||||
w_sc_data_tree = wrapped_tree(cache, ss, scid)
|
||||
w_sc_data_tree = dvm.Wrapped_tree(cache, ss, scid)
|
||||
|
||||
entrypoint := tx.SCDATA.Value("entrypoint", rpc.DataString).(string)
|
||||
//fmt.Printf("We must call the SC %s function\n", entrypoint)
|
||||
|
||||
gas, err = chain.execute_sc_function(w_sc_tree, w_sc_data_tree, scid, bl_height, bl_topoheight, bl_timestamp, blid, tx, entrypoint, 1)
|
||||
balance, sc_parsed, found := dvm.ReadSC(w_sc_tree, w_sc_data_tree, scid)
|
||||
if found {
|
||||
gascompute, gasstorage, err = dvm.Execute_sc_function(w_sc_tree, w_sc_data_tree, scid, bl_height, bl_topoheight, bl_timestamp, blid, txhash, sc_parsed, entrypoint, 1, balance, signer, incoming_value, tx.SCDATA, tx.Fees(), chain.simulator)
|
||||
} else {
|
||||
logger.V(1).Error(nil, "SC not found", "scid", scid)
|
||||
err = fmt.Errorf("SC not found %s", scid)
|
||||
}
|
||||
|
||||
default: // unknown what to do
|
||||
err = fmt.Errorf("unknown action what to do scid %x", scid)
|
||||
@ -384,48 +378,7 @@ func (chain *Blockchain) process_transaction_sc(cache map[crypto.Hash]*graviton.
|
||||
// we must commit all the changes
|
||||
// check whether we are not overflowing/underflowing, means SC is not over sending
|
||||
if err == nil {
|
||||
total_per_asset := map[crypto.Hash]uint64{}
|
||||
for _, transfer := range w_sc_data_tree.transfere { // do external tranfer
|
||||
if transfer.Amount == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// an SCID can generate it's token infinitely
|
||||
if transfer.Asset != scid && total_per_asset[transfer.Asset]+transfer.Amount <= total_per_asset[transfer.Asset] {
|
||||
err = fmt.Errorf("Balance calculation overflow")
|
||||
break
|
||||
} else {
|
||||
total_per_asset[transfer.Asset] = total_per_asset[transfer.Asset] + transfer.Amount
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
for asset, value := range total_per_asset {
|
||||
stored_value, _ := chain.LoadSCAssetValue(w_sc_data_tree, scid, asset)
|
||||
// an SCID can generate it's token infinitely
|
||||
if asset != scid && stored_value-value > stored_value {
|
||||
err = fmt.Errorf("Balance calculation underflow stored_value %d transferring %d\n", stored_value, value)
|
||||
break
|
||||
}
|
||||
|
||||
var new_value [8]byte
|
||||
binary.BigEndian.PutUint64(new_value[:], stored_value-value)
|
||||
chain.StoreSCValue(w_sc_data_tree, scid, asset[:], new_value[:])
|
||||
}
|
||||
}
|
||||
|
||||
//also check whether all destinations are registered
|
||||
if err == nil {
|
||||
for _, transfer := range w_sc_data_tree.transfere {
|
||||
if _, err = balance_tree.Get([]byte(transfer.Address)); err == nil || xerrors.Is(err, graviton.ErrNotFound) {
|
||||
// everything is okay
|
||||
} else {
|
||||
err = fmt.Errorf("account is unregistered")
|
||||
logger.V(1).Error(err, "account is unregistered", "txhash", txhash, "scid", scid, "address", transfer.Address)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
err = dvm.SanityCheckExternalTransfers(w_sc_data_tree, balance_tree, scid)
|
||||
}
|
||||
|
||||
if err != nil { // error occured, give everything to SC, since we may not have information to send them back
|
||||
@ -433,111 +386,15 @@ func (chain *Blockchain) process_transaction_sc(cache map[crypto.Hash]*graviton.
|
||||
logger.Error(err, "error executing sc", "txid", txhash)
|
||||
}
|
||||
|
||||
for _, payload := range tx.Payloads {
|
||||
var new_value [8]byte
|
||||
|
||||
w_sc_data_tree = wrapped_tree(cache, ss, scid) // get a new tree, discarding everything
|
||||
|
||||
stored_value, _ := chain.LoadSCAssetValue(w_sc_data_tree, scid, payload.SCID)
|
||||
binary.BigEndian.PutUint64(new_value[:], stored_value+payload.BurnValue)
|
||||
chain.StoreSCValue(w_sc_data_tree, scid, payload.SCID[:], new_value[:])
|
||||
|
||||
for k, v := range w_sc_data_tree.entries { // commit incoming balances to tree
|
||||
if err = w_sc_data_tree.tree.Put([]byte(k), v); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
//for k, v := range w_sc_tree.entries {
|
||||
// if err = w_sc_tree.tree.Put([]byte(k), v); err != nil {
|
||||
// return
|
||||
// }
|
||||
//}
|
||||
|
||||
if signer, err1 := Extract_signer(&tx); err1 == nil { // if we can identify sender, return funds to him
|
||||
dvm.ErrorRevert(ss, cache, balance_tree, signer, scid, incoming_value)
|
||||
} else { // we could not extract signer, give burned funds to SC
|
||||
dvm.ErrorRevert(ss, cache, balance_tree, signer, scid, incoming_value)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// anything below should never give error
|
||||
if _, ok := cache[scid]; !ok {
|
||||
cache[scid] = w_sc_data_tree.tree
|
||||
}
|
||||
|
||||
for k, v := range w_sc_data_tree.entries { // commit entire data to tree
|
||||
if _, ok := globals.Arguments["--debug"]; ok && globals.Arguments["--debug"] != nil && chain.simulator {
|
||||
logger.V(1).Info("Writing", "txid", txhash, "scid", scid, "key", fmt.Sprintf("%x", k), "value", fmt.Sprintf("%x", v))
|
||||
}
|
||||
if len(v) == 0 {
|
||||
if err = w_sc_data_tree.tree.Delete([]byte(k)); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if err = w_sc_data_tree.tree.Put([]byte(k), v); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range w_sc_tree.entries {
|
||||
if err = w_sc_tree.tree.Put([]byte(k), v); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for i, transfer := range w_sc_data_tree.transfere { // do external tranfer
|
||||
if transfer.Amount == 0 {
|
||||
continue
|
||||
}
|
||||
//fmt.Printf("%d sending to external %s %x\n", i,transfer.Asset,transfer.Address)
|
||||
var zeroscid crypto.Hash
|
||||
|
||||
var curbtree *graviton.Tree
|
||||
switch transfer.Asset {
|
||||
case zeroscid: // main dero balance, handle it
|
||||
curbtree = balance_tree
|
||||
case scid: // this scid balance, handle it
|
||||
curbtree = cache[scid]
|
||||
default: // any other asset scid
|
||||
var ok bool
|
||||
if curbtree, ok = cache[transfer.Asset]; !ok {
|
||||
if curbtree, err = ss.GetTree(string(transfer.Asset[:])); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cache[transfer.Asset] = curbtree
|
||||
}
|
||||
}
|
||||
|
||||
if curbtree == nil {
|
||||
panic("tree cannot be nil at this point in time")
|
||||
}
|
||||
|
||||
addr_bytes := []byte(transfer.Address)
|
||||
if _, err = balance_tree.Get(addr_bytes); err != nil { // first check whether address is registered
|
||||
err = fmt.Errorf("sending to non registered account acc %x err %s", addr_bytes, err) // this can only occur, if account no registered or dis corruption
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var balance_serialized []byte
|
||||
balance_serialized, err = curbtree.Get(addr_bytes)
|
||||
if err != nil && xerrors.Is(err, graviton.ErrNotFound) { // if the address is not found, lookup in main tree
|
||||
var p bn256.G1
|
||||
if err = p.DecodeCompressed(addr_bytes[:]); err != nil {
|
||||
panic(fmt.Errorf("key %x could not be decompressed", addr_bytes))
|
||||
}
|
||||
|
||||
balance := crypto.ConstructElGamal(&p, crypto.ElGamal_BASE_G) // init zero balance
|
||||
nb := crypto.NonceBalance{NonceHeight: 0, Balance: balance}
|
||||
balance_serialized = nb.Serialize()
|
||||
} else if err != nil {
|
||||
fmt.Printf("%s %d could not transfer %d %+v\n", scid, i, transfer.Amount, addr_bytes)
|
||||
panic(err) // only disk corruption can reach here
|
||||
}
|
||||
|
||||
nb := new(crypto.NonceBalance).Deserialize(balance_serialized)
|
||||
nb.Balance = nb.Balance.Plus(new(big.Int).SetUint64(transfer.Amount)) // add transfer to users balance homomorphically
|
||||
curbtree.Put(addr_bytes, nb.Serialize()) // reserialize and store
|
||||
}
|
||||
dvm.ProcessExternal(ss, cache, balance_tree, signer, scid, w_sc_data_tree, w_sc_tree)
|
||||
|
||||
//c := w_sc_data_tree.tree.Cursor()
|
||||
//for k, v, err := c.First(); err == nil; k, v, err = c.Next() {
|
||||
@ -553,7 +410,7 @@ func (chain *Blockchain) process_transaction_sc(cache map[crypto.Hash]*graviton.
|
||||
|
||||
// func extract signer from a tx, if possible
|
||||
// extract signer is only possible if ring size is 2
|
||||
func extract_signer(tx *transaction.Transaction) (signer [33]byte, err error) {
|
||||
func Extract_signer(tx *transaction.Transaction) (signer [33]byte, err error) {
|
||||
for t := range tx.Payloads {
|
||||
if uint64(len(tx.Payloads[t].Statement.Publickeylist_compressed)) != tx.Payloads[t].Statement.RingSize {
|
||||
panic("tx is not expanded")
|
||||
|
@ -177,7 +177,7 @@ func handle_easymenu_post_open_command(l *readline.Instance, line string) (proce
|
||||
}
|
||||
|
||||
if ConfirmYesNoDefaultNo(l, "Confirm Transaction (y/N)") {
|
||||
tx, err := wallet.TransferPayload0([]rpc.Transfer{rpc.Transfer{SCID: scid, Amount: amount_to_transfer, Destination: a.String()}}, 0, false, rpc.Arguments{}, false) // empty SCDATA
|
||||
tx, err := wallet.TransferPayload0([]rpc.Transfer{rpc.Transfer{SCID: scid, Amount: amount_to_transfer, Destination: a.String()}}, 0, false, rpc.Arguments{}, 0, false) // empty SCDATA
|
||||
|
||||
if err != nil {
|
||||
logger.Error(err, "Error while building Transaction")
|
||||
@ -332,7 +332,7 @@ func handle_easymenu_post_open_command(l *readline.Instance, line string) (proce
|
||||
|
||||
//src_port := uint64(0xffffffffffffffff)
|
||||
|
||||
tx, err := wallet.TransferPayload0([]rpc.Transfer{rpc.Transfer{Amount: amount_to_transfer, Destination: a.String(), Payload_RPC: arguments}}, 0, false, rpc.Arguments{}, false) // empty SCDATA
|
||||
tx, err := wallet.TransferPayload0([]rpc.Transfer{rpc.Transfer{Amount: amount_to_transfer, Destination: a.String(), Payload_RPC: arguments}}, 0, false, rpc.Arguments{}, 0, false) // empty SCDATA
|
||||
|
||||
if err != nil {
|
||||
logger.Error(err, "Error while building Transaction")
|
||||
|
@ -216,7 +216,7 @@ func handle_prompt_command(l *readline.Instance, line string) {
|
||||
|
||||
//uid, err := wallet.PoolTransferWithBurn(addr, send_amount, burn_amount, data, rpc.Arguments{})
|
||||
|
||||
tx, err := wallet.TransferPayload0([]rpc.Transfer{rpc.Transfer{Amount: send_amount, Burn: burn_amount, Destination: addr}}, 0, false, rpc.Arguments{}, false) // empty SCDATA
|
||||
tx, err := wallet.TransferPayload0([]rpc.Transfer{rpc.Transfer{Amount: send_amount, Burn: burn_amount, Destination: addr}}, 0, false, rpc.Arguments{}, 0, false) // empty SCDATA
|
||||
|
||||
if err != nil {
|
||||
logger.Error(err, "Error while building Transaction")
|
||||
|
93
cmd/derod/rpc/rpc_dero_estimategas.go
Normal file
93
cmd/derod/rpc/rpc_dero_estimategas.go
Normal file
@ -0,0 +1,93 @@
|
||||
// Copyright 2017-2021 DERO Project. All rights reserved.
|
||||
// Use of this source code in any form is governed by RESEARCH license.
|
||||
// license can be found in the LICENSE file.
|
||||
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
|
||||
//
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package rpc
|
||||
|
||||
import "fmt"
|
||||
import "context"
|
||||
import "strings"
|
||||
|
||||
//import "encoding/binary"
|
||||
import "encoding/base64"
|
||||
import "runtime/debug"
|
||||
|
||||
import "github.com/deroproject/derohe/cryptography/crypto"
|
||||
|
||||
//import "github.com/deroproject/derohe/config"
|
||||
import "github.com/deroproject/derohe/rpc"
|
||||
|
||||
import "github.com/deroproject/derohe/dvm"
|
||||
|
||||
//import "github.com/deroproject/derohe/transaction"
|
||||
//import "github.com/deroproject/derohe/blockchain"
|
||||
|
||||
import "github.com/deroproject/graviton"
|
||||
|
||||
func GetGasEstimate(ctx context.Context, p rpc.GasEstimate_Params) (result rpc.GasEstimate_Result, err error) {
|
||||
defer func() { // safety so if anything wrong happens, we return error
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("panic occured. stack trace r %s %s", r, debug.Stack())
|
||||
}
|
||||
}()
|
||||
|
||||
if len(p.SC_Code) >= 1 && !strings.Contains(strings.ToLower(p.SC_Code), "initialize") { // decode SC from base64 if possible, since json hash limitations
|
||||
if sc, err := base64.StdEncoding.DecodeString(p.SC_Code); err == nil {
|
||||
p.SC_Code = string(sc)
|
||||
}
|
||||
}
|
||||
|
||||
var signer *rpc.Address
|
||||
|
||||
if len(p.Signer) > 0 {
|
||||
if signer, err = rpc.NewAddress(p.Signer); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
incoming_values := map[crypto.Hash]uint64{}
|
||||
for _, t := range p.Transfers {
|
||||
if t.Burn > 0 {
|
||||
incoming_values[t.SCID] += t.Burn
|
||||
}
|
||||
}
|
||||
|
||||
toporecord, err := chain.Store.Topo_store.Read(chain.Load_TOPO_HEIGHT())
|
||||
// we must now fill in compressed ring members
|
||||
if err == nil {
|
||||
var ss *graviton.Snapshot
|
||||
ss, err = chain.Store.Balance_store.LoadSnapshot(toporecord.State_Version)
|
||||
if err == nil {
|
||||
s := dvm.SimulatorInitialize(ss)
|
||||
if len(p.SC_Code) >= 1 { // we need to install the SC
|
||||
if _, result.GasCompute, result.GasStorage, err = s.SCInstall(p.SC_Code, incoming_values, p.SC_RPC, signer, 0); err != nil {
|
||||
return
|
||||
}
|
||||
} else { // we need to estimate gas for already installed contract
|
||||
if result.GasCompute, result.GasStorage, err = s.RunSC(incoming_values, p.SC_RPC, signer, 0); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//fmt.Printf("p %+v\n", p)
|
||||
|
||||
result.Status = "OK"
|
||||
err = nil
|
||||
|
||||
//logger.Debugf("result %+v\n", result);
|
||||
return
|
||||
}
|
@ -17,6 +17,7 @@
|
||||
package rpc
|
||||
|
||||
import "fmt"
|
||||
import "bytes"
|
||||
import "context"
|
||||
import "runtime/debug"
|
||||
import "github.com/deroproject/derohe/config"
|
||||
@ -26,6 +27,7 @@ import "github.com/deroproject/derohe/rpc"
|
||||
|
||||
//import "github.com/deroproject/derohe/blockchain"
|
||||
|
||||
// only give random members who have not been used in last 5 blocks
|
||||
func GetRandomAddress(ctx context.Context, p rpc.GetRandomAddress_Params) (result rpc.GetRandomAddress_Result, err error) {
|
||||
defer func() { // safety so if anything wrong happens, we return error
|
||||
if r := recover(); r != nil {
|
||||
@ -33,9 +35,10 @@ func GetRandomAddress(ctx context.Context, p rpc.GetRandomAddress_Params) (resul
|
||||
}
|
||||
}()
|
||||
topoheight := chain.Load_TOPO_HEIGHT()
|
||||
old_topoheight := topoheight
|
||||
|
||||
if topoheight > 100 {
|
||||
topoheight -= 5
|
||||
if old_topoheight > 100 {
|
||||
old_topoheight -= 5
|
||||
}
|
||||
|
||||
var cursor_list []string
|
||||
@ -43,14 +46,22 @@ func GetRandomAddress(ctx context.Context, p rpc.GetRandomAddress_Params) (resul
|
||||
{
|
||||
|
||||
toporecord, err := chain.Store.Topo_store.Read(topoheight)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
toporecord_old, err := chain.Store.Topo_store.Read(old_topoheight)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ss, err := chain.Store.Balance_store.LoadSnapshot(toporecord.State_Version)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ss_old, err := chain.Store.Balance_store.LoadSnapshot(toporecord_old.State_Version)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
treename := config.BALANCE_TREE
|
||||
if !p.SCID.IsZero() {
|
||||
@ -61,15 +72,27 @@ func GetRandomAddress(ctx context.Context, p rpc.GetRandomAddress_Params) (resul
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
balance_tree_old, err := ss_old.GetTree(treename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
account_map := map[string]bool{}
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
|
||||
k, _, err := balance_tree.Random()
|
||||
k, v, err := balance_tree.Random()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
v_old, err := balance_tree_old.Get(k)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if bytes.Compare(v, v_old) != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var acckey crypto.Point
|
||||
if err := acckey.DecodeCompressed(k[:]); err != nil {
|
||||
|
@ -30,7 +30,6 @@ import "github.com/deroproject/derohe/rpc"
|
||||
import "github.com/deroproject/derohe/dvm"
|
||||
|
||||
//import "github.com/deroproject/derohe/transaction"
|
||||
import "github.com/deroproject/derohe/blockchain"
|
||||
|
||||
import "github.com/deroproject/graviton"
|
||||
|
||||
@ -87,7 +86,7 @@ func GetSC(ctx context.Context, p rpc.GetSC_Params) (result rpc.GetSC_Result, er
|
||||
if p.Code { // give SC code
|
||||
var code_bytes []byte
|
||||
var v dvm.Variable
|
||||
if code_bytes, err = sc_data_tree.Get(blockchain.SC_Code_Key(scid)); err == nil {
|
||||
if code_bytes, err = sc_data_tree.Get(dvm.SC_Code_Key(scid)); err == nil {
|
||||
if err = v.UnmarshalBinary(code_bytes); err != nil {
|
||||
result.Code = "Unmarshal error"
|
||||
} else {
|
||||
|
@ -24,8 +24,10 @@ import "runtime/debug"
|
||||
|
||||
//import "github.com/romana/rlog"
|
||||
import "github.com/deroproject/derohe/cryptography/crypto"
|
||||
import "github.com/deroproject/derohe/cryptography/bn256"
|
||||
import "github.com/deroproject/derohe/config"
|
||||
import "github.com/deroproject/derohe/rpc"
|
||||
import "github.com/deroproject/derohe/dvm"
|
||||
import "github.com/deroproject/derohe/globals"
|
||||
import "github.com/deroproject/derohe/transaction"
|
||||
import "github.com/deroproject/derohe/blockchain"
|
||||
@ -115,7 +117,7 @@ func GetTransaction(ctx context.Context, p rpc.GetTransaction_Params) (result rp
|
||||
|
||||
if sc_data_tree, err := ss.GetTree(string(scid[:])); err == nil {
|
||||
var code_bytes []byte
|
||||
if code_bytes, err = sc_data_tree.Get(blockchain.SC_Code_Key(scid)); err == nil {
|
||||
if code_bytes, err = sc_data_tree.Get(dvm.SC_Code_Key(scid)); err == nil {
|
||||
related.Code = string(code_bytes)
|
||||
|
||||
}
|
||||
@ -149,6 +151,15 @@ func GetTransaction(ctx context.Context, p rpc.GetTransaction_Params) (result rp
|
||||
related.Ring = append(related.Ring, ring)
|
||||
}
|
||||
|
||||
if signer, err1 := blockchain.Extract_signer(&tx); err1 == nil {
|
||||
var p bn256.G1
|
||||
if err = p.DecodeCompressed(signer[:]); err == nil {
|
||||
s := rpc.NewAddressFromKeys((*crypto.Point)(&p))
|
||||
s.Mainnet = globals.Config.Name == config.Mainnet.Name
|
||||
related.Signer = s.String()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -115,11 +115,14 @@ func Notify_MiniBlock_Addition() {
|
||||
chain.RPC_NotifyNewMiniBlock.L.Lock()
|
||||
chain.RPC_NotifyNewMiniBlock.Wait()
|
||||
chain.RPC_NotifyNewMiniBlock.L.Unlock()
|
||||
|
||||
if globals.Arguments["--simulator"] == nil || (globals.Arguments["--simulator"] != nil && globals.Arguments["--simulator"].(bool) == false) {
|
||||
go func() {
|
||||
defer globals.Recover(2)
|
||||
SendJob()
|
||||
}()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Notify_Height_Changes() {
|
||||
@ -310,6 +313,7 @@ var historical_apis = handler.Map{"getinfo": handler.New(GetInfo),
|
||||
"getblocktemplate": handler.New(GetBlockTemplate),
|
||||
"getencryptedbalance": handler.New(GetEncryptedBalance),
|
||||
"getsc": handler.New(GetSC),
|
||||
"getgasestimate": handler.New(GetGasEstimate),
|
||||
"nametoaddress": handler.New(NameToAddress)}
|
||||
|
||||
var servicemux = handler.ServiceMap{
|
||||
@ -331,6 +335,7 @@ var servicemux = handler.ServiceMap{
|
||||
"GetBlockTemplate": handler.New(GetBlockTemplate),
|
||||
"GetEncryptedBalance": handler.New(GetEncryptedBalance),
|
||||
"GetSC": handler.New(GetSC),
|
||||
"GetGasEstimate": handler.New(GetGasEstimate),
|
||||
"NameToAddress": handler.New(NameToAddress),
|
||||
},
|
||||
"DAEMON": handler.Map{
|
||||
|
@ -474,6 +474,7 @@ func load_tx_info_from_tx(info *txinfo, tx *transaction.Transaction) (err error)
|
||||
|
||||
if tx.TransactionType == transaction.SC_TX {
|
||||
info.SC_Args = tx.SCDATA
|
||||
|
||||
}
|
||||
|
||||
// if outputs cannot be located, do not panic
|
||||
@ -556,6 +557,10 @@ func load_tx_from_rpc(info *txinfo, txhash string) (err error) {
|
||||
|
||||
info.Ring = tx_result.Txs[0].Ring
|
||||
|
||||
if tx.TransactionType == transaction.SC_TX {
|
||||
info.SC_Signer = "Unknown"
|
||||
}
|
||||
|
||||
if tx.TransactionType == transaction.NORMAL || tx.TransactionType == transaction.BURN_TX || tx.TransactionType == transaction.SC_TX {
|
||||
|
||||
for t := range tx.Payloads {
|
||||
@ -570,6 +575,7 @@ func load_tx_from_rpc(info *txinfo, txhash string) (err error) {
|
||||
|
||||
a.Ring_size = len(tx_result.Txs[0].Ring[t])
|
||||
a.Ring = tx_result.Txs[0].Ring[t]
|
||||
info.SC_Signer = tx_result.Txs[0].Signer
|
||||
|
||||
info.Assets = append(info.Assets, a)
|
||||
|
||||
|
@ -103,8 +103,13 @@
|
||||
|
||||
{{range $ii, $ee := .info.Assets}}
|
||||
{{if eq $ee.SCID "0000000000000000000000000000000000000000000000000000000000000000" }}
|
||||
|
||||
|
||||
|
||||
<H5>DERO : {{$ee.Ring_size}} inputs/outputs (RING size) Fees {{$ee.Fees}}
|
||||
|
||||
|
||||
|
||||
{{if eq $.info.TransactionType "SC"}}
|
||||
Deposited to SC {{$ee.Burn}}
|
||||
{{else}}
|
||||
@ -112,6 +117,7 @@
|
||||
{{end}}
|
||||
|
||||
</H5>
|
||||
{{if eq $.info.TransactionType "SC"}} <H5>Sender : {{ $.info.SC_Signer }} </H5> {{end}}
|
||||
|
||||
{{else}}
|
||||
<H5>Token: {{$ee.SCID}} {{$ee.Ring_size}} inputs/outputs (RING size) Fees {{$ee.Fees}} {{if eq $.info.TransactionType "SC"}}
|
||||
|
@ -211,7 +211,7 @@ func Test_Creation_TX(t *testing.T) {
|
||||
// here we are collecting proofs for later on bennhcmarking
|
||||
for j := 2; j <= 128; j = j * 2 {
|
||||
wsrc.SetRingSize(j)
|
||||
tx, err := wsrc.TransferPayload0([]rpc.Transfer{rpc.Transfer{Destination: wdst.GetAddress().String(), Amount: 1}}, 0, false, rpc.Arguments{}, false)
|
||||
tx, err := wsrc.TransferPayload0([]rpc.Transfer{rpc.Transfer{Destination: wdst.GetAddress().String(), Amount: 1}}, 0, false, rpc.Arguments{}, 0, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot create transaction, err %s", err)
|
||||
} else {
|
||||
@ -228,7 +228,7 @@ func Test_Creation_TX(t *testing.T) {
|
||||
wdst.SetRingSize(2)
|
||||
|
||||
// accounts are reversed
|
||||
reverse_tx, err := wdst.TransferPayload0([]rpc.Transfer{rpc.Transfer{Destination: wsrc.GetAddress().String(), Amount: 1}}, 0, false, rpc.Arguments{}, false)
|
||||
reverse_tx, err := wdst.TransferPayload0([]rpc.Transfer{rpc.Transfer{Destination: wsrc.GetAddress().String(), Amount: 1}}, 0, false, rpc.Arguments{}, 0, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot create transaction, err %s", err)
|
||||
}
|
||||
@ -242,7 +242,7 @@ func Test_Creation_TX(t *testing.T) {
|
||||
pre_transfer_src_balance, _ := wsrc.Get_Balance()
|
||||
pre_transfer_dst_balance, _ := wdst.Get_Balance()
|
||||
|
||||
tx, err := wsrc.TransferPayload0([]rpc.Transfer{rpc.Transfer{Destination: wdst.GetAddress().String(), Amount: 1}}, 0, false, rpc.Arguments{}, false)
|
||||
tx, err := wsrc.TransferPayload0([]rpc.Transfer{rpc.Transfer{Destination: wdst.GetAddress().String(), Amount: 1}}, 0, false, rpc.Arguments{}, 0, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot create transaction, err %s", err)
|
||||
} else {
|
||||
@ -284,7 +284,7 @@ func Test_Creation_TX(t *testing.T) {
|
||||
var tx_set []*transaction.Transaction
|
||||
|
||||
for i := 0; i < 6; i++ {
|
||||
tx, err := wsrc.TransferPayload0([]rpc.Transfer{rpc.Transfer{Destination: wdst.GetAddress().String(), Amount: 1}}, 0, false, rpc.Arguments{}, false)
|
||||
tx, err := wsrc.TransferPayload0([]rpc.Transfer{rpc.Transfer{Destination: wdst.GetAddress().String(), Amount: 1}}, 0, false, rpc.Arguments{}, 0, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot create transaction, err %s", err)
|
||||
} else {
|
||||
|
@ -21,6 +21,7 @@ import "os"
|
||||
import "time"
|
||||
import "fmt"
|
||||
import "bytes"
|
||||
import "errors"
|
||||
|
||||
import "strings"
|
||||
import "strconv"
|
||||
@ -67,7 +68,7 @@ DERO : A secure, private blockchain with smart-contracts
|
||||
Simulates DERO block single node which helps in development and tests
|
||||
|
||||
Usage:
|
||||
simulator [--help] [--version] [--testnet] [--debug] [--sync-node] [--data-dir=<directory>] [--rpc-bind=<127.0.0.1:9999>] [--http-address=<0.0.0.0:8080>] [--clog-level=1] [--flog-level=1]
|
||||
simulator [--help] [--version] [--testnet] [--debug] [--noautomine] [--sync-node] [--data-dir=<directory>] [--rpc-bind=<127.0.0.1:9999>] [--http-address=<0.0.0.0:8080>] [--clog-level=1] [--flog-level=1]
|
||||
simulator -h | --help
|
||||
simulator --version
|
||||
|
||||
@ -76,6 +77,7 @@ Options:
|
||||
--version Show version.
|
||||
--testnet Run in testnet mode.
|
||||
--debug Debug mode enabled, print more log messages
|
||||
--noautomine No blocks will be mined (except genesis), used for testing, supported only on linux
|
||||
--clog-level=1 Set console log level (0 to 127)
|
||||
--flog-level=1 Set file log level (0 to 127)
|
||||
--data-dir=<directory> Store blockchain data at this location
|
||||
@ -89,6 +91,8 @@ var logger logr.Logger
|
||||
|
||||
var rpcport = "127.0.0.1:20000"
|
||||
|
||||
var TRIGGER_MINE_BLOCK string = "/dev/shm/mineblocknow"
|
||||
|
||||
const wallet_ports_start = 30000 // all wallets will rpc activated on ports
|
||||
|
||||
// this is a crude function used during tests
|
||||
@ -100,16 +104,17 @@ func Mine_block_single(chain *blockchain.Blockchain, miner_address rpc.Address)
|
||||
// return fmt.Errorf("this function can only run in simulator mode")
|
||||
//}
|
||||
|
||||
for i := uint64(0); i < config.BLOCK_TIME-config.MINIBLOCK_HIGHDIFF; i++ {
|
||||
for {
|
||||
bl, mbl, _, _, err := chain.Create_new_block_template_mining(miner_address)
|
||||
if err != nil {
|
||||
logger.Error(err, "err while request block template")
|
||||
return err
|
||||
}
|
||||
if _, blid, _, err = chain.Accept_new_block(bl.Timestamp, mbl.Serialize()); blid.IsZero() || err != nil {
|
||||
if err != nil {
|
||||
if _, blid, _, err = chain.Accept_new_block(bl.Timestamp, mbl.Serialize()); err != nil {
|
||||
logger.Error(err, "err while accepting block template")
|
||||
}
|
||||
return err
|
||||
} else if !blid.IsZero() {
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -546,26 +551,46 @@ exit:
|
||||
}
|
||||
}
|
||||
|
||||
func exists(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
return !errors.Is(err, os.ErrNotExist)
|
||||
}
|
||||
|
||||
func trigger_block_creation() {
|
||||
fmt.Printf("triggering fie creation\n")
|
||||
if globals.Arguments["--noautomine"].(bool) == true {
|
||||
err := os.WriteFile(TRIGGER_MINE_BLOCK, []byte("HELLO"), 0666)
|
||||
fmt.Printf("triggering fie creation %s err %s\n", TRIGGER_MINE_BLOCK, err)
|
||||
}
|
||||
}
|
||||
|
||||
// generate a block as soon as tx appears in blockchain
|
||||
// or 15 sec pass
|
||||
func mine_block_auto(chain *blockchain.Blockchain, miner_address rpc.Address) {
|
||||
|
||||
last_block_time := time.Now()
|
||||
for {
|
||||
bl, _, _, _, err := chain.Create_new_block_template_mining(miner_address)
|
||||
if err != nil {
|
||||
logger.Error(err, "error while building mining block")
|
||||
}
|
||||
|
||||
if time.Now().Sub(last_block_time) > time.Duration(config.BLOCK_TIME)*time.Second || // every X secs generate a block
|
||||
len(bl.Tx_hashes) >= 1 { //pools have a tx, try to mine them ASAP
|
||||
|
||||
if err := Mine_block_single(chain, miner_address); err != nil {
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
if globals.Arguments["--noautomine"].(bool) == true && exists(TRIGGER_MINE_BLOCK) {
|
||||
if err = Mine_block_single(chain, miner_address); err == nil {
|
||||
last_block_time = time.Now()
|
||||
|
||||
os.Remove(TRIGGER_MINE_BLOCK)
|
||||
} else {
|
||||
logger.Error(err, "error while mining single block")
|
||||
}
|
||||
}
|
||||
if globals.Arguments["--noautomine"].(bool) == false {
|
||||
if time.Now().Sub(last_block_time) > time.Duration(config.BLOCK_TIME)*time.Second || // every X secs generate a block
|
||||
len(bl.Tx_hashes) >= 1 { //pools have a tx, try to mine them ASAP
|
||||
if err := Mine_block_single(chain, miner_address); err == nil {
|
||||
last_block_time = time.Now()
|
||||
}
|
||||
}
|
||||
}
|
||||
time.Sleep(900 * time.Millisecond)
|
||||
}
|
||||
|
@ -39,8 +39,12 @@ const SC_META = "M" // keeps all SCs balance, their state, their OWNER, the
|
||||
// one are open SCs, which provide i/o privacy
|
||||
// one are private SCs which are truly private, in which no one has visibility of io or functionality
|
||||
|
||||
// 10.25 MB block every 12 secs is equal to roughly 410 TX per second
|
||||
// if we consider side blocks, TPS increase to > 500 TPS
|
||||
// this limits the contract size or amount of data it can store per interaction
|
||||
const MAX_STORAGE_GAS_ATOMIC_UNITS = 20000
|
||||
|
||||
// Minimum FEE calculation constants are here
|
||||
const FEE_PER_KB = uint64(100) // .00100 dero per kb
|
||||
|
||||
// we can easily improve TPS by changing few parameters in this file
|
||||
// the resources compute/network may not be easy for the developing countries
|
||||
// we need to trade of TPS as per community
|
||||
@ -51,9 +55,6 @@ const STARGATE_HE_MAX_TX_SIZE = 300 * 1024 // max size
|
||||
const MIN_RINGSIZE = 2 // >= 2 , ringsize will be accepted
|
||||
const MAX_RINGSIZE = 128 // <= 128, ringsize will be accepted
|
||||
|
||||
// Minimum FEE calculation constants are here
|
||||
const FEE_PER_KB = uint64(100) // .00100 dero per kb
|
||||
|
||||
type SettingsStruct struct {
|
||||
MAINNET_BOOTSTRAP_DIFFICULTY uint64 `env:"MAINNET_BOOTSTRAP_DIFFICULTY" envDefault:"80000000"`
|
||||
MAINNET_MINIMUM_DIFFICULTY uint64 `env:"MAINNET_MINIMUM_DIFFICULTY" envDefault:"80000000"`
|
||||
@ -106,7 +107,7 @@ var Mainnet = CHAIN_CONFIG{Name: "mainnet",
|
||||
}
|
||||
|
||||
var Testnet = CHAIN_CONFIG{Name: "testnet", // testnet will always have last 3 bytes 0
|
||||
Network_ID: uuid.FromBytesOrNil([]byte{0x59, 0xd7, 0xf7, 0xe9, 0xdd, 0x48, 0xd5, 0xfd, 0x13, 0x0a, 0xf6, 0xe0, 0x77, 0x00, 0x00, 0x00}),
|
||||
Network_ID: uuid.FromBytesOrNil([]byte{0x59, 0xd7, 0xf7, 0xe9, 0xdd, 0x48, 0xd5, 0xfd, 0x13, 0x0a, 0xf6, 0xe0, 0x78, 0x00, 0x00, 0x00}),
|
||||
GETWORK_Default_Port: 10100,
|
||||
P2P_Default_Port: 40401,
|
||||
RPC_Default_Port: 40402,
|
||||
|
@ -20,4 +20,4 @@ import "github.com/blang/semver/v4"
|
||||
|
||||
// right now it has to be manually changed
|
||||
// do we need to include git commitsha??
|
||||
var Version = semver.MustParse("3.4.99-0.DEROHE.STARGATE+03012022")
|
||||
var Version = semver.MustParse("3.4.103-0.DEROHE.STARGATE+18012022")
|
||||
|
110
dvm/dvm.go
110
dvm/dvm.go
@ -157,10 +157,10 @@ func check_valid_name(name string) bool {
|
||||
}
|
||||
|
||||
func check_valid_type(name string) Vtype {
|
||||
switch name {
|
||||
case "Uint64":
|
||||
switch strings.ToLower(name) {
|
||||
case "uint64":
|
||||
return Uint64
|
||||
case "String":
|
||||
case "string":
|
||||
return String
|
||||
}
|
||||
return Invalid
|
||||
@ -406,9 +406,16 @@ type Blockchain_Input struct {
|
||||
// this is necessary to prevent number of attacks
|
||||
type Shared_State struct {
|
||||
SCIDZERO crypto.Hash // points to DERO SCID , which is zero
|
||||
SCIDSELF crypto.Hash // points to SELF SCID
|
||||
SCIDSELF crypto.Hash // points to SELF SCID, this separation is necessary, if we enable cross SC calls
|
||||
// but note they bring all sorts of mess, bugs
|
||||
Persistance bool // whether the results will be persistant or it's just a demo/test call
|
||||
Trace bool // enables tracing to screen
|
||||
GasComputeUsed int64
|
||||
GasComputeLimit int64
|
||||
GasComputeCheck bool // if gascheck is true, bail out as soon as limit is breached
|
||||
GasStoreUsed int64
|
||||
GasStoreLimit int64
|
||||
GasStoreCheck bool // storage gas, bail out as soon as limit is breached
|
||||
|
||||
Chain_inputs *Blockchain_Input // all blockchain info is available here
|
||||
|
||||
@ -416,6 +423,8 @@ type Shared_State struct {
|
||||
Assets_Transfer map[string]map[string]uint64 // any Assets that this TX wants to send OUT
|
||||
// transfers are only processed after the contract has terminated successfully
|
||||
|
||||
RamStore map[Variable]Variable
|
||||
|
||||
RND *RND // this is initialized only once while invoking entrypoint
|
||||
Store *TX_Storage // mechanism to access a data store, can discard changes
|
||||
|
||||
@ -425,10 +434,28 @@ type Shared_State struct {
|
||||
|
||||
}
|
||||
|
||||
//consumr and check compute gas
|
||||
func (state *Shared_State) ConsumeGas(c int64) {
|
||||
if state != nil {
|
||||
state.GasComputeUsed += c
|
||||
if state.GasComputeCheck && state.GasComputeUsed > state.GasComputeLimit {
|
||||
panic("Insufficient Gas")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// consume and check storage gas
|
||||
func (state *Shared_State) ConsumeStorageGas(c int64) {
|
||||
if state != nil {
|
||||
state.GasStoreUsed += c
|
||||
if state.GasStoreCheck && state.GasStoreUsed > state.GasStoreLimit {
|
||||
panic("Insufficient Storage Gas")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type DVM_Interpreter struct {
|
||||
Version semver.Version // current version set by setversion
|
||||
Cost int64
|
||||
CostLimit int64
|
||||
SCID string
|
||||
SC *SmartContract
|
||||
EntryPoint string
|
||||
@ -449,10 +476,8 @@ type DVM_Interpreter struct {
|
||||
|
||||
func (i *DVM_Interpreter) incrementIP(newip uint64) (line []string, err error) {
|
||||
var ok bool
|
||||
|
||||
try_again:
|
||||
|
||||
// increase cost here
|
||||
|
||||
if newip == 0 { // we are simply falling through
|
||||
index := i.f.LinesNumberIndex[i.IP] // find the pos in the line numbers and find the current line_number
|
||||
index++
|
||||
@ -493,6 +518,8 @@ func (i *DVM_Interpreter) interpret_SmartContract() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
i.State.ConsumeGas(5000) // every line number has some gas costs
|
||||
|
||||
newIP = 0 // this is necessary otherwise, it will trigger an infinite loop in the case given below
|
||||
|
||||
/*
|
||||
@ -963,6 +990,8 @@ func IsZero(value interface{}) uint64 {
|
||||
|
||||
func (dvm *DVM_Interpreter) evalBinaryExpr(exp *ast.BinaryExpr) interface{} {
|
||||
|
||||
dvm.State.ConsumeGas(800) // every expr evaluation has some cost
|
||||
|
||||
left := dvm.eval(exp.X)
|
||||
right := dvm.eval(exp.Y)
|
||||
|
||||
@ -992,7 +1021,6 @@ func (dvm *DVM_Interpreter) evalBinaryExpr(exp *ast.BinaryExpr) interface{} {
|
||||
return uint64(1)
|
||||
}
|
||||
return uint64(0)
|
||||
|
||||
}
|
||||
|
||||
// handle string operands
|
||||
@ -1002,6 +1030,9 @@ func (dvm *DVM_Interpreter) evalBinaryExpr(exp *ast.BinaryExpr) interface{} {
|
||||
|
||||
switch exp.Op {
|
||||
case token.ADD:
|
||||
if len(left_string)+len(right_string) >= 1024*1024 {
|
||||
panic("too big string value")
|
||||
}
|
||||
return left_string + right_string
|
||||
case token.EQL:
|
||||
if left_string == right_string {
|
||||
@ -1016,7 +1047,6 @@ func (dvm *DVM_Interpreter) evalBinaryExpr(exp *ast.BinaryExpr) interface{} {
|
||||
default:
|
||||
panic(fmt.Sprintf("String data type only support addition operation ('%s') not supported", exp.Op))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
left_uint64 := left.(uint64)
|
||||
@ -1075,61 +1105,3 @@ func (dvm *DVM_Interpreter) evalBinaryExpr(exp *ast.BinaryExpr) interface{} {
|
||||
}
|
||||
return uint64(0)
|
||||
}
|
||||
|
||||
/*
|
||||
func main() {
|
||||
|
||||
const src = `
|
||||
Function HelloWorld(s Uint64) Uint64
|
||||
|
||||
5
|
||||
10 Dim x1, x2 as Uint64
|
||||
20 LET x1 = 3
|
||||
25 LET x1 = 3 + 5 - 1
|
||||
27 LET x2 = x1 + 3
|
||||
28 RETURN HelloWorld2(s*s)
|
||||
30 Printf "x1=%d x2=%d s = %d" x1 x2 s
|
||||
35 IF x1 == 7 THEN GOTO 100 ELSE GOTO 38
|
||||
38 Dim y1, y2 as String
|
||||
40 LET y1 = "first string" + "second string"
|
||||
|
||||
|
||||
60 GOTO 100
|
||||
80 GOTO 10
|
||||
100 RETURN 0
|
||||
500 LET y = 45
|
||||
501 y = 45
|
||||
|
||||
End Function
|
||||
|
||||
|
||||
Function HelloWorld2(s Uint64) Uint64
|
||||
|
||||
900 Return s
|
||||
950 y = 45
|
||||
// Comment begins at column 5.
|
||||
|
||||
; This line should not be included in the output.
|
||||
REM jj
|
||||
|
||||
|
||||
|
||||
7000 let x.ku[1+1]=0x55
|
||||
End Function
|
||||
|
||||
`
|
||||
|
||||
// we should be build an AST here
|
||||
|
||||
sc, pos, err := ParseSmartContract(src)
|
||||
if err != nil {
|
||||
fmt.Printf("Error while parsing smart contract pos %s err : %s\n", pos, err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := RunSmartContract(&sc, "HelloWorld", map[string]interface{}{"s": "9999"})
|
||||
|
||||
fmt.Printf("result %+v err %s\n", result, err)
|
||||
|
||||
}
|
||||
*/
|
||||
|
@ -39,74 +39,81 @@ import "github.com/deroproject/derohe/cryptography/crypto"
|
||||
// this needs more investigation
|
||||
// also, more investigation is required to enable predetermined external oracles
|
||||
|
||||
type DVM_FUNCTION_PTR func(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{})
|
||||
type DVM_FUNCTION_PTR_UINT64 func(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64)
|
||||
type DVM_FUNCTION_PTR_STRING func(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result string)
|
||||
type DVM_FUNCTION_PTR_ANY func(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{})
|
||||
|
||||
var func_table = map[string][]func_data{}
|
||||
|
||||
type func_data struct {
|
||||
Range semver.Range
|
||||
Cost int64
|
||||
Ptr DVM_FUNCTION_PTR
|
||||
ComputeCost int64
|
||||
StorageCost int64
|
||||
PtrU DVM_FUNCTION_PTR_UINT64
|
||||
PtrS DVM_FUNCTION_PTR_STRING
|
||||
Ptr DVM_FUNCTION_PTR_ANY
|
||||
}
|
||||
|
||||
func init() {
|
||||
func_table["version"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_version}}
|
||||
func_table["load"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_load}}
|
||||
func_table["exists"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_exists}}
|
||||
func_table["store"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_store}}
|
||||
func_table["delete"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_delete}}
|
||||
func_table["random"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_random}}
|
||||
func_table["scid"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_scid}}
|
||||
func_table["blid"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_blid}}
|
||||
func_table["txid"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_txid}}
|
||||
func_table["dero"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_dero}}
|
||||
func_table["block_height"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_block_height}}
|
||||
func_table["block_timestamp"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_block_timestamp}}
|
||||
func_table["signer"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_signer}}
|
||||
func_table["update_sc_code"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_update_sc_code}}
|
||||
func_table["is_address_valid"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_is_address_valid}}
|
||||
func_table["address_raw"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_address_raw}}
|
||||
func_table["address_string"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_address_string}}
|
||||
func_table["send_dero_to_address"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_send_dero_to_address}}
|
||||
func_table["send_asset_to_address"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_send_asset_to_address}}
|
||||
func_table["derovalue"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_derovalue}}
|
||||
func_table["assetvalue"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_assetvalue}}
|
||||
func_table["atoi"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_atoi}}
|
||||
func_table["itoa"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_itoa}}
|
||||
func_table["sha256"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_sha256}}
|
||||
func_table["sha3256"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_sha3256}}
|
||||
func_table["keccak256"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_keccak256}}
|
||||
func_table["hex"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_hex}}
|
||||
func_table["hexdecode"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_hexdecode}}
|
||||
func_table["min"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_min}}
|
||||
func_table["max"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_max}}
|
||||
func_table["strlen"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_strlen}}
|
||||
func_table["substr"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), Cost: 1, Ptr: dvm_substr}}
|
||||
}
|
||||
|
||||
func (dvm *DVM_Interpreter) process_cost(c int64) {
|
||||
dvm.Cost += c
|
||||
|
||||
// TODO check cost overflow
|
||||
func_table["version"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 1000, StorageCost: 0, PtrU: dvm_version}}
|
||||
func_table["load"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 5000, StorageCost: 0, Ptr: dvm_load}}
|
||||
func_table["exists"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 5000, StorageCost: 0, PtrU: dvm_exists}}
|
||||
func_table["store"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 10000, StorageCost: 0, PtrU: dvm_store}}
|
||||
func_table["delete"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 3000, StorageCost: 0, PtrU: dvm_delete}}
|
||||
func_table["mapexists"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 1000, StorageCost: 0, PtrU: dvm_mapexists}}
|
||||
func_table["mapget"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 1000, StorageCost: 0, Ptr: dvm_mapget}}
|
||||
func_table["mapstore"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 1000, StorageCost: 0, PtrU: dvm_mapstore}}
|
||||
func_table["mapdelete"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 1000, StorageCost: 0, PtrU: dvm_mapdelete}}
|
||||
func_table["random"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 2500, StorageCost: 0, PtrU: dvm_random}}
|
||||
func_table["scid"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 2000, StorageCost: 0, PtrS: dvm_scid}}
|
||||
func_table["blid"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 2000, StorageCost: 0, PtrS: dvm_blid}}
|
||||
func_table["txid"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 2000, StorageCost: 0, PtrS: dvm_txid}}
|
||||
func_table["dero"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 10000, StorageCost: 0, PtrS: dvm_dero}}
|
||||
func_table["block_height"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 2000, StorageCost: 0, PtrU: dvm_block_height}}
|
||||
func_table["block_timestamp"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 2500, StorageCost: 0, PtrU: dvm_block_timestamp}}
|
||||
func_table["signer"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 5000, StorageCost: 0, PtrS: dvm_signer}}
|
||||
func_table["update_sc_code"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 5000, StorageCost: 0, PtrU: dvm_update_sc_code}}
|
||||
func_table["is_address_valid"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 50000, StorageCost: 0, PtrU: dvm_is_address_valid}}
|
||||
func_table["address_raw"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 60000, StorageCost: 0, PtrS: dvm_address_raw}}
|
||||
func_table["address_string"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 50000, StorageCost: 0, PtrS: dvm_address_string}}
|
||||
func_table["send_dero_to_address"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 70000, StorageCost: 0, PtrU: dvm_send_dero_to_address}}
|
||||
func_table["send_asset_to_address"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 90000, StorageCost: 0, PtrU: dvm_send_asset_to_address}}
|
||||
func_table["derovalue"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 10000, StorageCost: 0, PtrU: dvm_derovalue}}
|
||||
func_table["assetvalue"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 10000, StorageCost: 0, PtrU: dvm_assetvalue}}
|
||||
func_table["atoi"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 5000, StorageCost: 0, PtrU: dvm_atoi}}
|
||||
func_table["itoa"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 5000, StorageCost: 0, PtrS: dvm_itoa}}
|
||||
func_table["sha256"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 25000, StorageCost: 0, PtrS: dvm_sha256}}
|
||||
func_table["sha3256"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 25000, StorageCost: 0, PtrS: dvm_sha3256}}
|
||||
func_table["keccak256"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 25000, StorageCost: 0, PtrS: dvm_keccak256}}
|
||||
func_table["hex"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 10000, StorageCost: 0, PtrS: dvm_hex}}
|
||||
func_table["hexdecode"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 10000, StorageCost: 0, PtrS: dvm_hexdecode}}
|
||||
func_table["min"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 5000, StorageCost: 0, PtrU: dvm_min}}
|
||||
func_table["max"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 5000, StorageCost: 0, PtrU: dvm_max}}
|
||||
func_table["strlen"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 20000, StorageCost: 0, PtrU: dvm_strlen}}
|
||||
func_table["substr"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 20000, StorageCost: 0, PtrS: dvm_substr}}
|
||||
func_table["panic"] = []func_data{func_data{Range: semver.MustParseRange(">=0.0.0"), ComputeCost: 10000, StorageCost: 0, PtrU: dvm_panic}}
|
||||
}
|
||||
|
||||
// this will handle all internal functions which may be required/necessary to expand DVM functionality
|
||||
func (dvm *DVM_Interpreter) Handle_Internal_Function(expr *ast.CallExpr, func_name string) (handled bool, result interface{}) {
|
||||
var err error
|
||||
_ = err
|
||||
|
||||
if funcs, ok := func_table[strings.ToLower(func_name)]; ok {
|
||||
for _, f := range funcs {
|
||||
if func_data_array, ok := func_table[strings.ToLower(func_name)]; ok {
|
||||
for _, f := range func_data_array {
|
||||
if f.Range(dvm.Version) {
|
||||
dvm.process_cost(f.Cost)
|
||||
dvm.State.ConsumeGas(f.ComputeCost)
|
||||
if f.PtrU != nil {
|
||||
return f.PtrU(dvm, expr)
|
||||
} else if f.PtrS != nil {
|
||||
return f.PtrS(dvm, expr)
|
||||
} else {
|
||||
return f.Ptr(dvm, expr)
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
panic("function doesnot match any version")
|
||||
}
|
||||
//panic("function does not exist")
|
||||
return false, nil // function does not exist
|
||||
}
|
||||
|
||||
// the load/store functions are sandboxed and thus cannot affect any other SC storage
|
||||
@ -124,7 +131,6 @@ func (dvm *DVM_Interpreter) Load(key Variable) interface{} {
|
||||
default:
|
||||
panic("Unhandled data_type")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// whether a variable exists in store or not
|
||||
@ -142,10 +148,28 @@ func (dvm *DVM_Interpreter) Delete(key Variable) {
|
||||
dvm.State.Store.Delete(DataKey{SCID: dvm.State.Chain_inputs.SCID, Key: key})
|
||||
}
|
||||
|
||||
func dvm_version(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 1 { // expression without limit
|
||||
panic("version expects 1 parameters")
|
||||
// we should migrate to generics ASAP
|
||||
func convertdatatovariable(datai interface{}) Variable {
|
||||
switch k := datai.(type) {
|
||||
case uint64:
|
||||
return Variable{Type: Uint64, ValueUint64: k}
|
||||
case string:
|
||||
return Variable{Type: String, ValueString: k}
|
||||
default:
|
||||
panic("This variable cannot be loaded")
|
||||
}
|
||||
}
|
||||
|
||||
// checks whether necessary number of arguments have been provided
|
||||
func checkargscount(expected, actual int) {
|
||||
if expected != actual {
|
||||
panic("incorrect number of arguments")
|
||||
}
|
||||
}
|
||||
|
||||
func dvm_version(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64) {
|
||||
checkargscount(1, len(expr.Args)) // check number of arguments
|
||||
|
||||
if version_str, ok := dvm.eval(expr.Args[0]).(string); !ok {
|
||||
panic("unsupported version format")
|
||||
} else {
|
||||
@ -155,86 +179,78 @@ func dvm_version(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result
|
||||
}
|
||||
|
||||
func dvm_load(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 1 {
|
||||
panic("Load function expects a single varible as parameter")
|
||||
}
|
||||
checkargscount(1, len(expr.Args)) // check number of arguments
|
||||
key := dvm.eval(expr.Args[0])
|
||||
switch k := key.(type) {
|
||||
case uint64:
|
||||
return true, dvm.Load(Variable{Type: Uint64, ValueUint64: k})
|
||||
case string:
|
||||
return true, dvm.Load(Variable{Type: String, ValueString: k})
|
||||
default:
|
||||
panic("This variable cannot be loaded")
|
||||
}
|
||||
return true, dvm.Load(convertdatatovariable(key))
|
||||
|
||||
}
|
||||
|
||||
func dvm_exists(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 1 {
|
||||
panic("Exists function expects a single varible as parameter")
|
||||
}
|
||||
func dvm_exists(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64) {
|
||||
checkargscount(1, len(expr.Args)) // check number of arguments
|
||||
key := dvm.eval(expr.Args[0]) // evaluate the argument and use the result
|
||||
switch k := key.(type) {
|
||||
case uint64:
|
||||
return true, dvm.Exists(Variable{Type: Uint64, ValueUint64: k})
|
||||
case string:
|
||||
return true, dvm.Exists(Variable{Type: String, ValueString: k})
|
||||
default:
|
||||
panic("This variable cannot be loaded")
|
||||
}
|
||||
return true, dvm.Exists(convertdatatovariable(key))
|
||||
}
|
||||
|
||||
func dvm_store(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 2 {
|
||||
panic("Store function expects 2 variables as parameter")
|
||||
}
|
||||
key_eval := dvm.eval(expr.Args[0])
|
||||
value_eval := dvm.eval(expr.Args[1])
|
||||
var key, value Variable
|
||||
switch k := key_eval.(type) {
|
||||
case uint64:
|
||||
key = Variable{Type: Uint64, ValueUint64: k}
|
||||
|
||||
case string:
|
||||
key = Variable{Type: String, ValueString: k}
|
||||
default:
|
||||
panic("This variable cannot be stored")
|
||||
}
|
||||
|
||||
switch k := value_eval.(type) {
|
||||
case uint64:
|
||||
value = Variable{Type: Uint64, ValueUint64: k}
|
||||
case string:
|
||||
value = Variable{Type: String, ValueString: k}
|
||||
default:
|
||||
panic("This variable cannot be stored")
|
||||
}
|
||||
func dvm_store(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64) {
|
||||
checkargscount(2, len(expr.Args)) // check number of arguments
|
||||
key := convertdatatovariable(dvm.eval(expr.Args[0]))
|
||||
value := convertdatatovariable(dvm.eval(expr.Args[1]))
|
||||
|
||||
dvm.Store(key, value)
|
||||
return true, nil
|
||||
return true, 1
|
||||
}
|
||||
|
||||
func dvm_delete(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 1 {
|
||||
panic("Delete function expects 2 variables as parameter")
|
||||
}
|
||||
key_eval := dvm.eval(expr.Args[0])
|
||||
var key Variable
|
||||
switch k := key_eval.(type) {
|
||||
case uint64:
|
||||
key = Variable{Type: Uint64, ValueUint64: k}
|
||||
|
||||
case string:
|
||||
key = Variable{Type: String, ValueString: k}
|
||||
default:
|
||||
panic("This variable cannot be deleted")
|
||||
}
|
||||
|
||||
func dvm_delete(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64) {
|
||||
checkargscount(1, len(expr.Args)) // check number of arguments
|
||||
key := convertdatatovariable(dvm.eval(expr.Args[0]))
|
||||
dvm.Delete(key)
|
||||
return true, nil
|
||||
return true, uint64(1)
|
||||
}
|
||||
|
||||
func dvm_random(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
func dvm_mapexists(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64) {
|
||||
checkargscount(1, len(expr.Args)) // check number of arguments
|
||||
key := convertdatatovariable(dvm.eval(expr.Args[0])) // evaluate the argument and use the result
|
||||
|
||||
if _, ok := dvm.State.RamStore[key]; ok {
|
||||
return true, uint64(1)
|
||||
}
|
||||
return true, uint64(0)
|
||||
|
||||
}
|
||||
|
||||
func dvm_mapget(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
checkargscount(1, len(expr.Args)) // check number of arguments
|
||||
key := convertdatatovariable(dvm.eval(expr.Args[0])) // evaluate the argument and use the result
|
||||
|
||||
v := dvm.State.RamStore[key]
|
||||
|
||||
if v.Type == Uint64 {
|
||||
return true, v.ValueUint64
|
||||
} else if v.Type == String {
|
||||
return true, v.ValueString
|
||||
} else {
|
||||
panic("This variable cannot be obtained")
|
||||
}
|
||||
}
|
||||
|
||||
func dvm_mapstore(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64) {
|
||||
checkargscount(2, len(expr.Args)) // check number of arguments
|
||||
key := convertdatatovariable(dvm.eval(expr.Args[0])) // evaluate the argument and use the result
|
||||
value := convertdatatovariable(dvm.eval(expr.Args[1])) // evaluate the argument and use the result
|
||||
|
||||
dvm.State.RamStore[key] = value
|
||||
return true, uint64(1)
|
||||
}
|
||||
|
||||
func dvm_mapdelete(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64) {
|
||||
checkargscount(1, len(expr.Args)) // check number of arguments
|
||||
key := convertdatatovariable(dvm.eval(expr.Args[0])) // evaluate the argument and use the result
|
||||
|
||||
delete(dvm.State.RamStore, key)
|
||||
return true, uint64(1)
|
||||
}
|
||||
|
||||
func dvm_random(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64) {
|
||||
if len(expr.Args) >= 2 {
|
||||
panic("RANDOM function expects 0 or 1 number as parameter")
|
||||
}
|
||||
@ -252,36 +268,26 @@ func dvm_random(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result
|
||||
}
|
||||
}
|
||||
|
||||
func dvm_scid(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 0 {
|
||||
panic("SCID function expects 0 parameters")
|
||||
}
|
||||
func dvm_scid(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result string) {
|
||||
checkargscount(0, len(expr.Args)) // check number of arguments
|
||||
return true, string(dvm.State.Chain_inputs.SCID[:])
|
||||
}
|
||||
func dvm_blid(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 0 {
|
||||
panic("blid function expects 0 parameters")
|
||||
}
|
||||
func dvm_blid(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result string) {
|
||||
checkargscount(0, len(expr.Args)) // check number of arguments
|
||||
return true, string(dvm.State.Chain_inputs.BLID[:])
|
||||
}
|
||||
func dvm_txid(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 0 {
|
||||
panic("txid function expects 0 parameters")
|
||||
}
|
||||
func dvm_txid(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result string) {
|
||||
checkargscount(0, len(expr.Args)) // check number of arguments
|
||||
return true, string(dvm.State.Chain_inputs.TXID[:])
|
||||
}
|
||||
|
||||
func dvm_dero(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 0 {
|
||||
panic("dero function expects 0 parameters")
|
||||
}
|
||||
func dvm_dero(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result string) {
|
||||
checkargscount(0, len(expr.Args)) // check number of arguments
|
||||
var zerohash crypto.Hash
|
||||
return true, string(zerohash[:])
|
||||
}
|
||||
func dvm_block_height(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 0 {
|
||||
panic("BLOCK_HEIGHT function expects 0 parameters")
|
||||
}
|
||||
func dvm_block_height(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64) {
|
||||
checkargscount(0, len(expr.Args)) // check number of arguments
|
||||
return true, dvm.State.Chain_inputs.BL_HEIGHT
|
||||
}
|
||||
|
||||
@ -293,24 +299,18 @@ func dvm_block_topoheight(dvm *DVM_Interpreter, expr *ast.CallExpr)(handled bool
|
||||
return true, dvm.State.Chain_inputs.BL_TOPOHEIGHT
|
||||
}
|
||||
*/
|
||||
func dvm_block_timestamp(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 0 {
|
||||
panic("BLOCK_TIMESTAMP function expects 0 parameters")
|
||||
}
|
||||
func dvm_block_timestamp(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64) {
|
||||
checkargscount(0, len(expr.Args)) // check number of arguments
|
||||
return true, dvm.State.Chain_inputs.BL_TIMESTAMP
|
||||
}
|
||||
|
||||
func dvm_signer(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 0 {
|
||||
panic("SIGNER function expects 0 parameters")
|
||||
}
|
||||
func dvm_signer(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result string) {
|
||||
checkargscount(0, len(expr.Args)) // check number of arguments
|
||||
return true, dvm.State.Chain_inputs.Signer
|
||||
}
|
||||
|
||||
func dvm_update_sc_code(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 1 {
|
||||
panic("UPDATE_SC_CODE function expects 1 parameters")
|
||||
}
|
||||
func dvm_update_sc_code(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64) {
|
||||
checkargscount(1, len(expr.Args)) // check number of arguments
|
||||
code_eval := dvm.eval(expr.Args[0])
|
||||
switch k := code_eval.(type) {
|
||||
case string:
|
||||
@ -321,10 +321,8 @@ func dvm_update_sc_code(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool,
|
||||
}
|
||||
}
|
||||
|
||||
func dvm_is_address_valid(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 1 {
|
||||
panic("IS_ADDRESS_VALID function expects 1 parameters")
|
||||
}
|
||||
func dvm_is_address_valid(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64) {
|
||||
checkargscount(1, len(expr.Args)) // check number of arguments
|
||||
|
||||
addr_eval := dvm.eval(expr.Args[0])
|
||||
switch k := addr_eval.(type) {
|
||||
@ -341,10 +339,8 @@ func dvm_is_address_valid(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled boo
|
||||
}
|
||||
}
|
||||
|
||||
func dvm_address_raw(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 1 {
|
||||
panic("ADDRESS_RAW function expects 1 parameters")
|
||||
}
|
||||
func dvm_address_raw(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result string) {
|
||||
checkargscount(1, len(expr.Args)) // check number of arguments
|
||||
|
||||
addr_eval := dvm.eval(expr.Args[0])
|
||||
switch k := addr_eval.(type) {
|
||||
@ -353,16 +349,14 @@ func dvm_address_raw(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, re
|
||||
return true, string(addr.Compressed())
|
||||
}
|
||||
|
||||
return true, nil // fallthrough not supported in type switch
|
||||
return true, "" // fallthrough not supported in type switch
|
||||
default:
|
||||
return true, nil
|
||||
return true, ""
|
||||
}
|
||||
}
|
||||
|
||||
func dvm_address_string(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 1 {
|
||||
panic("ADDRESS_STRING function expects 1 parameters")
|
||||
}
|
||||
func dvm_address_string(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result string) {
|
||||
checkargscount(1, len(expr.Args)) // check number of arguments
|
||||
|
||||
addr_eval := dvm.eval(expr.Args[0])
|
||||
switch k := addr_eval.(type) {
|
||||
@ -374,16 +368,14 @@ func dvm_address_string(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool,
|
||||
return true, addr.String()
|
||||
}
|
||||
|
||||
return true, nil // fallthrough not supported in type switch
|
||||
return true, "" // fallthrough not supported in type switch
|
||||
default:
|
||||
return true, nil
|
||||
return true, ""
|
||||
}
|
||||
}
|
||||
|
||||
func dvm_send_dero_to_address(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 2 {
|
||||
panic("SEND_DERO_TO_ADDRESS function expects 2 parameters")
|
||||
}
|
||||
func dvm_send_dero_to_address(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64) {
|
||||
checkargscount(2, len(expr.Args)) // check number of arguments
|
||||
|
||||
addr_eval := dvm.eval(expr.Args[0])
|
||||
amount_eval := dvm.eval(expr.Args[1])
|
||||
@ -397,16 +389,14 @@ func dvm_send_dero_to_address(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled
|
||||
}
|
||||
|
||||
if amount_eval.(uint64) == 0 {
|
||||
return true, amount_eval
|
||||
return true, amount_eval.(uint64)
|
||||
}
|
||||
var zerohash crypto.Hash
|
||||
dvm.State.Store.SendExternal(dvm.State.Chain_inputs.SCID, zerohash, addr_eval.(string), amount_eval.(uint64)) // add record for external transfer
|
||||
return true, amount_eval
|
||||
return true, amount_eval.(uint64)
|
||||
}
|
||||
func dvm_send_asset_to_address(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 3 {
|
||||
panic("SEND_ASSET_TO_ADDRESS function expects 3 parameters") // address, amount, asset
|
||||
}
|
||||
func dvm_send_asset_to_address(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64) {
|
||||
checkargscount(3, len(expr.Args)) // check number of arguments
|
||||
|
||||
addr_eval := dvm.eval(expr.Args[0])
|
||||
amount_eval := dvm.eval(expr.Args[1])
|
||||
@ -427,7 +417,7 @@ func dvm_send_asset_to_address(dvm *DVM_Interpreter, expr *ast.CallExpr) (handle
|
||||
//fmt.Printf("sending asset %x (%d) to address %x\n", asset_eval.(string), amount_eval.(uint64),[]byte(addr_eval.(string)))
|
||||
|
||||
if amount_eval.(uint64) == 0 {
|
||||
return true, amount_eval
|
||||
return true, amount_eval.(uint64)
|
||||
}
|
||||
|
||||
if len(asset_eval.(string)) != 32 {
|
||||
@ -438,21 +428,18 @@ func dvm_send_asset_to_address(dvm *DVM_Interpreter, expr *ast.CallExpr) (handle
|
||||
|
||||
dvm.State.Store.SendExternal(dvm.State.Chain_inputs.SCID, asset, addr_eval.(string), amount_eval.(uint64)) // add record for external transfer
|
||||
|
||||
return true, amount_eval
|
||||
return true, amount_eval.(uint64)
|
||||
}
|
||||
|
||||
func dvm_derovalue(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 0 { // expression without limit
|
||||
panic("DEROVALUE expects no parameters")
|
||||
} else {
|
||||
func dvm_derovalue(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64) {
|
||||
checkargscount(0, len(expr.Args)) // check number of arguments
|
||||
return true, dvm.State.Assets[dvm.State.SCIDZERO]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func dvm_assetvalue(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 1 { // expression without limit
|
||||
panic("assetVALUE expects 1 parameters")
|
||||
} else {
|
||||
func dvm_assetvalue(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64) {
|
||||
checkargscount(1, len(expr.Args)) // check number of arguments
|
||||
|
||||
asset_eval := dvm.eval(expr.Args[0])
|
||||
|
||||
if _, ok := asset_eval.(string); !ok {
|
||||
@ -465,13 +452,12 @@ func dvm_assetvalue(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, res
|
||||
copy(asset[:], ([]byte(asset_eval.(string))))
|
||||
|
||||
return true, dvm.State.Assets[asset]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func dvm_itoa(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 1 { // expression without limit
|
||||
panic("itoa expects 1 parameters")
|
||||
} else {
|
||||
func dvm_itoa(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result string) {
|
||||
checkargscount(1, len(expr.Args)) // check number of arguments
|
||||
|
||||
asset_eval := dvm.eval(expr.Args[0])
|
||||
|
||||
if _, ok := asset_eval.(uint64); !ok {
|
||||
@ -479,13 +465,12 @@ func dvm_itoa(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result in
|
||||
}
|
||||
|
||||
return true, fmt.Sprintf("%d", asset_eval.(uint64))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func dvm_atoi(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 1 { // expression without limit
|
||||
panic("itoa expects 1 parameters")
|
||||
} else {
|
||||
func dvm_atoi(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64) {
|
||||
checkargscount(1, len(expr.Args)) // check number of arguments
|
||||
|
||||
asset_eval := dvm.eval(expr.Args[0])
|
||||
|
||||
if _, ok := asset_eval.(string); !ok {
|
||||
@ -497,20 +482,18 @@ func dvm_atoi(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result in
|
||||
} else {
|
||||
return true, u
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func dvm_strlen(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 1 { // expression without limit
|
||||
panic("itoa expects 1 parameters")
|
||||
} else {
|
||||
func dvm_strlen(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64) {
|
||||
checkargscount(1, len(expr.Args)) // check number of arguments
|
||||
asset_eval := dvm.eval(expr.Args[0])
|
||||
|
||||
if _, ok := asset_eval.(string); !ok {
|
||||
panic("atoi argument must be valid string")
|
||||
}
|
||||
return true, uint64(len([]byte(asset_eval.(string))))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func substr(input string, start uint64, length uint64) string {
|
||||
@ -527,10 +510,8 @@ func substr(input string, start uint64, length uint64) string {
|
||||
return string(asbytes[start : start+length])
|
||||
}
|
||||
|
||||
func dvm_substr(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 3 { // expression without limit
|
||||
panic("substr expects 3 parameters")
|
||||
}
|
||||
func dvm_substr(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result string) {
|
||||
checkargscount(3, len(expr.Args)) // check number of arguments
|
||||
input_eval := dvm.eval(expr.Args[0])
|
||||
if _, ok := input_eval.(string); !ok {
|
||||
panic("input argument must be valid string")
|
||||
@ -547,10 +528,8 @@ func dvm_substr(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result
|
||||
return true, substr(input_eval.(string), offset_eval.(uint64), length_eval.(uint64))
|
||||
}
|
||||
|
||||
func dvm_sha256(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 1 { // expression without limit
|
||||
panic("sha256 expects 1 parameters")
|
||||
}
|
||||
func dvm_sha256(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result string) {
|
||||
checkargscount(1, len(expr.Args)) // check number of arguments
|
||||
input_eval := dvm.eval(expr.Args[0])
|
||||
if _, ok := input_eval.(string); !ok {
|
||||
panic("input argument must be valid string")
|
||||
@ -560,10 +539,8 @@ func dvm_sha256(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result
|
||||
return true, string(hash[:])
|
||||
}
|
||||
|
||||
func dvm_sha3256(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 1 { // expression without limit
|
||||
panic("sha3256 expects 1 parameters")
|
||||
}
|
||||
func dvm_sha3256(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result string) {
|
||||
checkargscount(1, len(expr.Args)) // check number of arguments
|
||||
input_eval := dvm.eval(expr.Args[0])
|
||||
if _, ok := input_eval.(string); !ok {
|
||||
panic("input argument must be valid string")
|
||||
@ -573,10 +550,8 @@ func dvm_sha3256(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result
|
||||
return true, string(hash[:])
|
||||
}
|
||||
|
||||
func dvm_keccak256(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 1 { // expression without limit
|
||||
panic("keccak256 expects 1 parameters")
|
||||
}
|
||||
func dvm_keccak256(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result string) {
|
||||
checkargscount(1, len(expr.Args)) // check number of arguments
|
||||
input_eval := dvm.eval(expr.Args[0])
|
||||
if _, ok := input_eval.(string); !ok {
|
||||
panic("input argument must be valid string")
|
||||
@ -588,20 +563,16 @@ func dvm_keccak256(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, resu
|
||||
return true, string(hash[:])
|
||||
}
|
||||
|
||||
func dvm_hex(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 1 { // expression without limit
|
||||
panic("hex expects 1 parameters")
|
||||
}
|
||||
func dvm_hex(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result string) {
|
||||
checkargscount(1, len(expr.Args)) // check number of arguments
|
||||
input_eval := dvm.eval(expr.Args[0])
|
||||
if _, ok := input_eval.(string); !ok {
|
||||
panic("input argument must be valid string")
|
||||
}
|
||||
return true, hex.EncodeToString([]byte(input_eval.(string)))
|
||||
}
|
||||
func dvm_hexdecode(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 1 { // expression without limit
|
||||
panic("hex expects 1 parameters")
|
||||
}
|
||||
func dvm_hexdecode(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result string) {
|
||||
checkargscount(1, len(expr.Args)) // check number of arguments
|
||||
input_eval := dvm.eval(expr.Args[0])
|
||||
if _, ok := input_eval.(string); !ok {
|
||||
panic("input argument must be valid string")
|
||||
@ -614,10 +585,9 @@ func dvm_hexdecode(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, resu
|
||||
}
|
||||
}
|
||||
|
||||
func dvm_min(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 2 { // expression without limit
|
||||
panic("min expects 2 parameters")
|
||||
}
|
||||
func dvm_min(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64) {
|
||||
checkargscount(2, len(expr.Args)) // check number of arguments
|
||||
|
||||
a1 := dvm.eval(expr.Args[0])
|
||||
if _, ok := a1.(uint64); !ok {
|
||||
panic("input argument must be uint64")
|
||||
@ -629,15 +599,13 @@ func dvm_min(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result int
|
||||
}
|
||||
|
||||
if a1.(uint64) < a2.(uint64) {
|
||||
return true, a1
|
||||
return true, a1.(uint64)
|
||||
}
|
||||
return true, a2
|
||||
return true, a2.(uint64)
|
||||
}
|
||||
|
||||
func dvm_max(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result interface{}) {
|
||||
if len(expr.Args) != 2 { // expression without limit
|
||||
panic("min expects 2 parameters")
|
||||
}
|
||||
func dvm_max(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64) {
|
||||
checkargscount(2, len(expr.Args)) // check number of arguments
|
||||
a1 := dvm.eval(expr.Args[0])
|
||||
if _, ok := a1.(uint64); !ok {
|
||||
panic("input argument must be uint64")
|
||||
@ -649,7 +617,12 @@ func dvm_max(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result int
|
||||
}
|
||||
|
||||
if a1.(uint64) > a2.(uint64) {
|
||||
return true, a1
|
||||
return true, a1.(uint64)
|
||||
}
|
||||
return true, a2
|
||||
return true, a2.(uint64)
|
||||
}
|
||||
|
||||
func dvm_panic(dvm *DVM_Interpreter, expr *ast.CallExpr) (handled bool, result uint64) {
|
||||
panic("panic function called")
|
||||
return true, uint64(0)
|
||||
}
|
||||
|
@ -219,6 +219,53 @@ var execution_tests_functions = []struct {
|
||||
nil,
|
||||
Variable{Type: String, ValueString: string("")},
|
||||
},
|
||||
{
|
||||
"mapget()",
|
||||
`Function TestRun(input String) String
|
||||
10 mapstore("input",input)
|
||||
30 return mapget("input") + mapget("input")
|
||||
End Function`,
|
||||
"TestRun",
|
||||
map[string]interface{}{"input": string("0123456789")},
|
||||
nil,
|
||||
Variable{Type: String, ValueString: string("01234567890123456789")},
|
||||
},
|
||||
{
|
||||
"mapget()",
|
||||
`Function TestRun(input String) String
|
||||
10 mapstore("input",input)
|
||||
15 mapstore("input",input+input)
|
||||
30 return mapget("input")
|
||||
End Function`,
|
||||
"TestRun",
|
||||
map[string]interface{}{"input": string("0123456789")},
|
||||
nil,
|
||||
Variable{Type: String, ValueString: string("01234567890123456789")},
|
||||
},
|
||||
|
||||
{
|
||||
"mapexists()",
|
||||
`Function TestRun(input String) Uint64
|
||||
10 mapstore("input",input)
|
||||
30 return mapexists("input") + mapexists("input1")
|
||||
End Function`,
|
||||
"TestRun",
|
||||
map[string]interface{}{"input": string("0123456789")},
|
||||
nil,
|
||||
Variable{Type: Uint64, ValueUint64: uint64(1)},
|
||||
},
|
||||
{
|
||||
"mapdelete()",
|
||||
`Function TestRun(input String) Uint64
|
||||
10 mapstore("input",input)
|
||||
15 mapdelete("input")
|
||||
30 return mapexists("input")
|
||||
End Function`,
|
||||
"TestRun",
|
||||
map[string]interface{}{"input": string("0123456789")},
|
||||
nil,
|
||||
Variable{Type: Uint64, ValueUint64: uint64(0)},
|
||||
},
|
||||
}
|
||||
|
||||
func decodeHex(s string) []byte {
|
||||
@ -238,7 +285,7 @@ func Test_FUNCTION_execution(t *testing.T) {
|
||||
}
|
||||
|
||||
state := &Shared_State{Chain_inputs: &Blockchain_Input{BL_HEIGHT: 5, BL_TIMESTAMP: 9, SCID: crypto.ZEROHASH,
|
||||
BLID: crypto.ZEROHASH, TXID: crypto.ZEROHASH}}
|
||||
BLID: crypto.ZEROHASH, TXID: crypto.ZEROHASH}, RamStore: map[Variable]Variable{}}
|
||||
result, err := RunSmartContract(&sc, test.EntryPoint, state, test.Args)
|
||||
switch {
|
||||
case test.Eerr == nil && err == nil:
|
||||
|
@ -29,12 +29,6 @@ type DataKey struct {
|
||||
Key Variable
|
||||
}
|
||||
|
||||
type DataAtom struct {
|
||||
Key DataKey
|
||||
Prev_Value Variable // previous Value if any
|
||||
Value Variable // current value if any
|
||||
}
|
||||
|
||||
type TransferInternal struct {
|
||||
Asset crypto.Hash `cbor:"Asset,omitempty" json:"Asset,omitempty"` // transfer this asset
|
||||
SCID string `cbor:"A,omitempty" json:"A,omitempty"` // transfer to this SCID
|
||||
@ -64,6 +58,8 @@ type TX_Storage struct {
|
||||
RawKeys map[string][]byte // this keeps the in-transit DB updates, just in case we have to discard instantly
|
||||
|
||||
Transfers map[crypto.Hash]SC_Transfers // all transfers ( internal/external )
|
||||
|
||||
State *Shared_State // only for book keeping of storage gas
|
||||
}
|
||||
|
||||
// initialize tx store
|
||||
@ -82,17 +78,13 @@ func (tx_store *TX_Storage) RawLoad(key []byte) (value []byte, found bool) {
|
||||
return
|
||||
}
|
||||
|
||||
func (tx_store *TX_Storage) RawStore(key []byte, value []byte) {
|
||||
tx_store.RawKeys[string(key)] = value
|
||||
return
|
||||
}
|
||||
|
||||
func (tx_store *TX_Storage) Delete(dkey DataKey) {
|
||||
tx_store.RawStore(dkey.MarshalBinaryPanic(), []byte{})
|
||||
tx_store.RawKeys[string(dkey.MarshalBinaryPanic())] = []byte{}
|
||||
return
|
||||
}
|
||||
|
||||
// this will load the variable, and if the key is found
|
||||
// loads are cheaper
|
||||
func (tx_store *TX_Storage) Load(dkey DataKey, found_value *uint64) (value Variable) {
|
||||
|
||||
//fmt.Printf("Loading %+v \n", dkey)
|
||||
@ -104,6 +96,15 @@ func (tx_store *TX_Storage) Load(dkey DataKey, found_value *uint64) (value Varia
|
||||
if err := value.UnmarshalBinary(result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if tx_store.State != nil {
|
||||
if value.Length() > 10 {
|
||||
tx_store.State.ConsumeStorageGas(value.Length() / 10)
|
||||
} else {
|
||||
tx_store.State.ConsumeStorageGas(1)
|
||||
}
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
@ -112,6 +113,13 @@ func (tx_store *TX_Storage) Load(dkey DataKey, found_value *uint64) (value Varia
|
||||
}
|
||||
|
||||
value = tx_store.DiskLoader(dkey, found_value)
|
||||
if tx_store.State != nil {
|
||||
if value.Length() > 10 {
|
||||
tx_store.State.ConsumeStorageGas(value.Length() / 10)
|
||||
} else {
|
||||
tx_store.State.ConsumeStorageGas(1)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@ -120,7 +128,10 @@ func (tx_store *TX_Storage) Load(dkey DataKey, found_value *uint64) (value Varia
|
||||
func (tx_store *TX_Storage) Store(dkey DataKey, v Variable) {
|
||||
//fmt.Printf("Storing request %+v : %+v\n", dkey, v)
|
||||
|
||||
tx_store.RawKeys[string(dkey.MarshalBinaryPanic())] = v.MarshalBinaryPanic()
|
||||
kbytes := dkey.MarshalBinaryPanic()
|
||||
vbytes := v.MarshalBinaryPanic()
|
||||
tx_store.State.ConsumeStorageGas(int64(len(vbytes)) * 1)
|
||||
tx_store.RawKeys[string(kbytes)] = vbytes
|
||||
}
|
||||
|
||||
// store variable
|
||||
@ -173,6 +184,22 @@ func (dkey DataKey) MarshalBinaryPanic() (ser []byte) {
|
||||
return
|
||||
}
|
||||
|
||||
func (v Variable) Length() (length int64) {
|
||||
switch v.Type {
|
||||
case Invalid:
|
||||
return
|
||||
case Uint64:
|
||||
var buf [binary.MaxVarintLen64]byte
|
||||
done := binary.PutUvarint(buf[:], v.ValueUint64) // uint64 data type
|
||||
length += int64(done) + 1
|
||||
case String:
|
||||
length = int64(len([]byte(v.ValueString)) + 1)
|
||||
default:
|
||||
panic("unknown variable type not implemented")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// these are used by lowest layers
|
||||
func (v Variable) MarshalBinary() (data []byte, err error) {
|
||||
switch v.Type {
|
||||
|
@ -1,77 +0,0 @@
|
||||
// Copyright 2017-2018 DERO Project. All rights reserved.
|
||||
// Use of this source code in any form is governed by RESEARCH license.
|
||||
// license can be found in the LICENSE file.
|
||||
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
|
||||
//
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package dvm
|
||||
|
||||
import "fmt"
|
||||
|
||||
// this file implements a RAM store backend for testing purposes
|
||||
|
||||
type Memory_Storage struct {
|
||||
Atoms []DataAtom // all modification operations have to played/reverse in this order
|
||||
Keys map[DataKey]Variable
|
||||
RawKeys map[string][]byte
|
||||
}
|
||||
|
||||
var Memory_Backend Memory_Storage
|
||||
|
||||
func init() {
|
||||
DVM_STORAGE_BACKEND = &Memory_Backend
|
||||
}
|
||||
|
||||
func (mem_store *Memory_Storage) RawLoad(key []byte) (value []byte, found bool) {
|
||||
value, found = mem_store.RawKeys[string(key)]
|
||||
return
|
||||
}
|
||||
|
||||
func (mem_store *Memory_Storage) RawStore(key []byte, value []byte) {
|
||||
mem_store.RawKeys[string(key)] = value
|
||||
return
|
||||
}
|
||||
|
||||
// this will load the variable, and if the key is found
|
||||
func (mem_store *Memory_Storage) Load(dkey DataKey, found_value *uint64) (value Variable) {
|
||||
|
||||
*found_value = 0
|
||||
// if it was modified in current TX, use it
|
||||
if result, ok := mem_store.Keys[dkey]; ok {
|
||||
*found_value = 1
|
||||
return result
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// store variable
|
||||
func (mem_store *Memory_Storage) Store(dkey DataKey, v Variable) {
|
||||
|
||||
fmt.Printf("Storing %+v : %+v\n", dkey, v)
|
||||
var found uint64
|
||||
old_value := mem_store.Load(dkey, &found)
|
||||
|
||||
var atom DataAtom
|
||||
atom.Key = dkey
|
||||
atom.Value = v
|
||||
if found != 0 {
|
||||
atom.Prev_Value = old_value
|
||||
} else {
|
||||
atom.Prev_Value = Variable{}
|
||||
}
|
||||
|
||||
mem_store.Keys[atom.Key] = atom.Value
|
||||
mem_store.Atoms = append(mem_store.Atoms, atom)
|
||||
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package blockchain
|
||||
package dvm
|
||||
|
||||
// this file implements necessary structure to SC handling
|
||||
|
||||
@ -24,12 +24,12 @@ import "runtime/debug"
|
||||
import "encoding/binary"
|
||||
import "github.com/deroproject/derohe/cryptography/crypto"
|
||||
|
||||
import "github.com/deroproject/derohe/dvm"
|
||||
|
||||
//import "github.com/deroproject/graviton"
|
||||
import "github.com/deroproject/derohe/config"
|
||||
import "github.com/deroproject/derohe/rpc"
|
||||
import "github.com/deroproject/derohe/globals"
|
||||
import "github.com/deroproject/derohe/transaction"
|
||||
import "github.com/deroproject/graviton"
|
||||
|
||||
//import "github.com/deroproject/derohe/transaction"
|
||||
|
||||
// currently DERO hash 2 contract types
|
||||
// 1 OPEN
|
||||
@ -60,47 +60,74 @@ func SC_Meta_Key(scid crypto.Hash) []byte {
|
||||
return scid[:]
|
||||
}
|
||||
func SC_Code_Key(scid crypto.Hash) []byte {
|
||||
return dvm.Variable{Type: dvm.String, ValueString: "C"}.MarshalBinaryPanic()
|
||||
return Variable{Type: String, ValueString: "C"}.MarshalBinaryPanic()
|
||||
}
|
||||
func SC_Asset_Key(asset crypto.Hash) []byte {
|
||||
return asset[:]
|
||||
}
|
||||
|
||||
// used to wrap a graviton tree, so it could be discarded at any time
|
||||
type Tree_Wrapper struct {
|
||||
Tree *graviton.Tree
|
||||
Entries map[string][]byte
|
||||
Transfere []TransferExternal
|
||||
}
|
||||
|
||||
func (t *Tree_Wrapper) Get(key []byte) ([]byte, error) {
|
||||
if value, ok := t.Entries[string(key)]; ok {
|
||||
return value, nil
|
||||
} else {
|
||||
return t.Tree.Get(key)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tree_Wrapper) Put(key []byte, value []byte) error {
|
||||
t.Entries[string(key)] = append([]byte{}, value...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// checks cache and returns a wrapped tree if possible
|
||||
func Wrapped_tree(cache map[crypto.Hash]*graviton.Tree, ss *graviton.Snapshot, id crypto.Hash) *Tree_Wrapper {
|
||||
if cached_tree, ok := cache[id]; ok { // tree is in cache return it
|
||||
return &Tree_Wrapper{Tree: cached_tree, Entries: map[string][]byte{}}
|
||||
}
|
||||
|
||||
if tree, err := ss.GetTree(string(id[:])); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
return &Tree_Wrapper{Tree: tree, Entries: map[string][]byte{}}
|
||||
}
|
||||
}
|
||||
|
||||
// this will process the SC transaction
|
||||
// the tx should only be processed , if it has been processed
|
||||
|
||||
func (chain *Blockchain) execute_sc_function(w_sc_tree *Tree_Wrapper, data_tree *Tree_Wrapper, scid crypto.Hash, bl_height, bl_topoheight, bl_timestamp uint64, bl_hash crypto.Hash, tx transaction.Transaction, entrypoint string, hard_fork_version_current int64) (gas uint64, err error) {
|
||||
func Execute_sc_function(w_sc_tree *Tree_Wrapper, data_tree *Tree_Wrapper, scid crypto.Hash, bl_height, bl_topoheight, bl_timestamp uint64, blid crypto.Hash, txid crypto.Hash, sc_parsed SmartContract, entrypoint string, hard_fork_version_current int64, balance_at_start uint64, signer [33]byte, incoming_value map[crypto.Hash]uint64, SCDATA rpc.Arguments, gasstorage_incoming uint64, simulator bool) (gascompute, gasstorage uint64, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil { // safety so if anything wrong happens, verification fails
|
||||
if err == nil {
|
||||
err = fmt.Errorf("Stack trace \n%s", debug.Stack())
|
||||
}
|
||||
logger.V(1).Error(err, "Recovered while rewinding chain,", "r", r, "stack trace", string(debug.Stack()))
|
||||
//logger.V(1).Error(err, "Recovered while rewinding chain,", "r", r, "stack trace", string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
|
||||
//fmt.Printf("executing entrypoint %s\n", entrypoint)
|
||||
//fmt.Printf("executing entrypoint %s values %+v feees %d\n", entrypoint, incoming_value, fees)
|
||||
|
||||
//if !tx.Verify_SC_Signature() { // if tx is not SC TX, or Signature could not be verified skip it
|
||||
// return
|
||||
//}
|
||||
|
||||
tx_hash := tx.GetHash()
|
||||
tx_store := dvm.Initialize_TX_store()
|
||||
tx_store := Initialize_TX_store()
|
||||
|
||||
// used as value loader from disk
|
||||
// this function is used to load any data required by the SC
|
||||
|
||||
balance_loader := func(key dvm.DataKey) (result uint64) {
|
||||
balance_loader := func(key DataKey) (result uint64) {
|
||||
var found bool
|
||||
_ = found
|
||||
result, found = chain.LoadSCAssetValue(data_tree, key.SCID, key.Asset)
|
||||
result, found = LoadSCAssetValue(data_tree, key.SCID, key.Asset)
|
||||
return result
|
||||
}
|
||||
|
||||
diskloader := func(key dvm.DataKey, found *uint64) (result dvm.Variable) {
|
||||
diskloader := func(key DataKey, found *uint64) (result Variable) {
|
||||
var exists bool
|
||||
if result, exists = chain.LoadSCValue(data_tree, key.SCID, key.MarshalBinaryPanic()); exists {
|
||||
if result, exists = LoadSCValue(data_tree, key.SCID, key.MarshalBinaryPanic()); exists {
|
||||
*found = uint64(1)
|
||||
}
|
||||
//fmt.Printf("Loading from disk %+v result %+v found status %+v \n", key, result, exists)
|
||||
@ -123,73 +150,48 @@ func (chain *Blockchain) execute_sc_function(w_sc_tree *Tree_Wrapper, data_tree
|
||||
return value, true
|
||||
}
|
||||
|
||||
balance, sc_parsed, found := chain.ReadSC(w_sc_tree, data_tree, scid)
|
||||
if !found {
|
||||
logger.V(1).Error(nil, "SC not found", "scid", scid)
|
||||
err = fmt.Errorf("SC not found %s", scid)
|
||||
return
|
||||
}
|
||||
//fmt.Printf("sc_parsed %+v\n", sc_parsed)
|
||||
// if we found the SC in parsed form, check whether entrypoint is found
|
||||
function, ok := sc_parsed.Functions[entrypoint]
|
||||
if !ok {
|
||||
logger.V(1).Error(fmt.Errorf("stored SC does not contain entrypoint"), "", "entrypoint", entrypoint, "scid", scid)
|
||||
err = fmt.Errorf("stored SC does not contain entrypoint '%s' scid %s \n", entrypoint, scid)
|
||||
return
|
||||
}
|
||||
_ = function
|
||||
|
||||
//fmt.Printf("entrypoint found '%s' scid %s\n", entrypoint, scid)
|
||||
//if len(sc_tx.Params) == 0 { // initialize params if not initialized earlier
|
||||
// sc_tx.Params = map[string]string{}
|
||||
//}
|
||||
//sc_tx.Params["value"] = fmt.Sprintf("%d", sc_tx.Value) // overide value
|
||||
|
||||
tx_store.DiskLoader = diskloader // hook up loading from chain
|
||||
tx_store.DiskLoaderRaw = diskloader_raw
|
||||
tx_store.BalanceLoader = balance_loader
|
||||
tx_store.BalanceAtStart = balance
|
||||
tx_store.SCID = scid
|
||||
|
||||
//fmt.Printf("tx store %v\n", tx_store)
|
||||
|
||||
// we can skip proof check, here
|
||||
if err = chain.Expand_Transaction_NonCoinbase(&tx); err != nil {
|
||||
return
|
||||
}
|
||||
signer, err := extract_signer(&tx)
|
||||
if err != nil { // allow anonymous SC transactions with condition that SC will not call Signer
|
||||
// this allows anonymous voting and numerous other applications
|
||||
// otherwise SC receives signer as all zeroes
|
||||
}
|
||||
|
||||
// setup block hash, height, topoheight correctly
|
||||
state := &dvm.Shared_State{
|
||||
state := &Shared_State{
|
||||
Store: tx_store,
|
||||
Assets: map[crypto.Hash]uint64{},
|
||||
RamStore: map[Variable]Variable{},
|
||||
SCIDSELF: scid,
|
||||
Chain_inputs: &dvm.Blockchain_Input{
|
||||
Chain_inputs: &Blockchain_Input{
|
||||
BL_HEIGHT: bl_height,
|
||||
BL_TOPOHEIGHT: uint64(bl_topoheight),
|
||||
BL_TIMESTAMP: bl_timestamp,
|
||||
SCID: scid,
|
||||
BLID: bl_hash,
|
||||
TXID: tx_hash,
|
||||
BLID: blid,
|
||||
TXID: txid,
|
||||
Signer: string(signer[:]),
|
||||
},
|
||||
}
|
||||
|
||||
if _, ok = globals.Arguments["--debug"]; ok && globals.Arguments["--debug"] != nil && chain.simulator {
|
||||
state.Trace = true // enable tracing for dvm simulator
|
||||
tx_store.DiskLoader = diskloader // hook up loading from chain
|
||||
tx_store.DiskLoaderRaw = diskloader_raw
|
||||
tx_store.BalanceLoader = balance_loader
|
||||
tx_store.BalanceAtStart = balance_at_start
|
||||
tx_store.SCID = scid
|
||||
tx_store.State = state
|
||||
|
||||
if _, ok = globals.Arguments["--debug"]; ok && globals.Arguments["--debug"] != nil && simulator {
|
||||
state.Trace = true // enable tracing for dvm simulator
|
||||
}
|
||||
|
||||
for _, payload := range tx.Payloads {
|
||||
for asset, value := range incoming_value {
|
||||
var new_value [8]byte
|
||||
stored_value, _ := chain.LoadSCAssetValue(data_tree, scid, payload.SCID)
|
||||
binary.BigEndian.PutUint64(new_value[:], stored_value+payload.BurnValue)
|
||||
chain.StoreSCValue(data_tree, scid, payload.SCID[:], new_value[:])
|
||||
state.Assets[payload.SCID] += payload.BurnValue
|
||||
stored_value, _ := LoadSCAssetValue(data_tree, scid, asset)
|
||||
binary.BigEndian.PutUint64(new_value[:], stored_value+value)
|
||||
StoreSCValue(data_tree, scid, asset[:], new_value[:])
|
||||
state.Assets[asset] += value
|
||||
}
|
||||
|
||||
// we have an entrypoint, now we must setup parameters and dvm
|
||||
@ -199,16 +201,16 @@ func (chain *Blockchain) execute_sc_function(w_sc_tree *Tree_Wrapper, data_tree
|
||||
for _, p := range function.Params {
|
||||
var zerohash crypto.Hash
|
||||
switch {
|
||||
case p.Type == dvm.Uint64 && p.Name == "value":
|
||||
case p.Type == Uint64 && p.Name == "value":
|
||||
params[p.Name] = fmt.Sprintf("%d", state.Assets[zerohash]) // overide value
|
||||
case p.Type == dvm.Uint64 && tx.SCDATA.Has(p.Name, rpc.DataUint64):
|
||||
params[p.Name] = fmt.Sprintf("%d", tx.SCDATA.Value(p.Name, rpc.DataUint64).(uint64))
|
||||
case p.Type == dvm.String && tx.SCDATA.Has(p.Name, rpc.DataString):
|
||||
params[p.Name] = tx.SCDATA.Value(p.Name, rpc.DataString).(string)
|
||||
case p.Type == dvm.String && tx.SCDATA.Has(p.Name, rpc.DataHash):
|
||||
h := tx.SCDATA.Value(p.Name, rpc.DataHash).(crypto.Hash)
|
||||
case p.Type == Uint64 && SCDATA.Has(p.Name, rpc.DataUint64):
|
||||
params[p.Name] = fmt.Sprintf("%d", SCDATA.Value(p.Name, rpc.DataUint64).(uint64))
|
||||
case p.Type == String && SCDATA.Has(p.Name, rpc.DataString):
|
||||
params[p.Name] = SCDATA.Value(p.Name, rpc.DataString).(string)
|
||||
case p.Type == String && SCDATA.Has(p.Name, rpc.DataHash):
|
||||
h := SCDATA.Value(p.Name, rpc.DataHash).(crypto.Hash)
|
||||
params[p.Name] = string(h[:])
|
||||
fmt.Printf("%s:%x\n", p.Name, string(h[:]))
|
||||
//fmt.Printf("%s:%x\n", p.Name, string(h[:]))
|
||||
|
||||
default:
|
||||
err = fmt.Errorf("entrypoint '%s' parameter type missing or not yet supported (%+v)", entrypoint, p)
|
||||
@ -216,22 +218,53 @@ func (chain *Blockchain) execute_sc_function(w_sc_tree *Tree_Wrapper, data_tree
|
||||
}
|
||||
}
|
||||
|
||||
result, err := dvm.RunSmartContract(&sc_parsed, entrypoint, state, params)
|
||||
state.GasComputeLimit = int64(10000000) // everyone has fixed amount of compute gas
|
||||
if state.GasComputeLimit > 0 {
|
||||
state.GasComputeCheck = true
|
||||
}
|
||||
|
||||
// gas consumed in parameters to avoid tx bloats
|
||||
if gasstorage_incoming > 0 {
|
||||
if gasstorage_incoming > config.MAX_STORAGE_GAS_ATOMIC_UNITS {
|
||||
gasstorage_incoming = config.MAX_STORAGE_GAS_ATOMIC_UNITS // whatever gas may be provided, upper limit of gas is this
|
||||
}
|
||||
|
||||
state.GasStoreLimit = int64(gasstorage_incoming)
|
||||
state.GasStoreCheck = true
|
||||
}
|
||||
|
||||
// deduct gas from whatever has been included in TX
|
||||
var scdata_bytes []byte
|
||||
if scdata_bytes, err = SCDATA.MarshalBinary(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
scdata_length := len(scdata_bytes)
|
||||
state.ConsumeStorageGas(int64(scdata_length))
|
||||
|
||||
result, err := RunSmartContract(&sc_parsed, entrypoint, state, params)
|
||||
|
||||
if state.GasComputeUsed > 0 {
|
||||
gascompute = uint64(state.GasComputeUsed)
|
||||
}
|
||||
if state.GasStoreUsed > 0 {
|
||||
gasstorage = uint64(state.GasStoreUsed)
|
||||
}
|
||||
|
||||
//fmt.Printf("result value %+v\n", result)
|
||||
|
||||
if err != nil {
|
||||
logger.V(2).Error(err, "error execcuting SC", "entrypoint", entrypoint, "scid", scid)
|
||||
//logger.V(2).Error(err, "error execcuting SC", "entrypoint", entrypoint, "scid", scid)
|
||||
return
|
||||
}
|
||||
|
||||
if err == nil && result.Type == dvm.Uint64 && result.ValueUint64 == 0 { // confirm the changes
|
||||
if err == nil && result.Type == Uint64 && result.ValueUint64 == 0 { // confirm the changes
|
||||
for k, v := range tx_store.RawKeys {
|
||||
chain.StoreSCValue(data_tree, scid, []byte(k), v)
|
||||
StoreSCValue(data_tree, scid, []byte(k), v)
|
||||
|
||||
// fmt.Printf("storing %x %x\n", k,v)
|
||||
}
|
||||
|
||||
data_tree.transfere = append(data_tree.transfere, tx_store.Transfers[scid].TransferE...)
|
||||
|
||||
data_tree.Transfere = append(data_tree.Transfere, tx_store.Transfers[scid].TransferE...)
|
||||
} else { // discard all changes, since we never write to store immediately, they are purged, however we need to return any value associated
|
||||
err = fmt.Errorf("Discarded knowingly")
|
||||
return
|
||||
@ -243,7 +276,7 @@ func (chain *Blockchain) execute_sc_function(w_sc_tree *Tree_Wrapper, data_tree
|
||||
}
|
||||
|
||||
// reads SC, balance
|
||||
func (chain *Blockchain) ReadSC(w_sc_tree *Tree_Wrapper, data_tree *Tree_Wrapper, scid crypto.Hash) (balance uint64, sc dvm.SmartContract, found bool) {
|
||||
func ReadSC(w_sc_tree *Tree_Wrapper, data_tree *Tree_Wrapper, scid crypto.Hash) (balance uint64, sc SmartContract, found bool) {
|
||||
meta_bytes, err := w_sc_tree.Get(SC_Meta_Key(scid))
|
||||
if err != nil {
|
||||
return
|
||||
@ -254,19 +287,19 @@ func (chain *Blockchain) ReadSC(w_sc_tree *Tree_Wrapper, data_tree *Tree_Wrapper
|
||||
return
|
||||
}
|
||||
var zerohash crypto.Hash
|
||||
balance, _ = chain.LoadSCAssetValue(data_tree, scid, zerohash)
|
||||
balance, _ = LoadSCAssetValue(data_tree, scid, zerohash)
|
||||
|
||||
sc_bytes, err := data_tree.Get(SC_Code_Key(scid))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var v dvm.Variable
|
||||
var v Variable
|
||||
if err = v.UnmarshalBinary(sc_bytes); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
sc, pos, err := dvm.ParseSmartContract(v.ValueString)
|
||||
sc, pos, err := ParseSmartContract(v.ValueString)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -277,7 +310,7 @@ func (chain *Blockchain) ReadSC(w_sc_tree *Tree_Wrapper, data_tree *Tree_Wrapper
|
||||
return
|
||||
}
|
||||
|
||||
func (chain *Blockchain) LoadSCValue(data_tree *Tree_Wrapper, scid crypto.Hash, key []byte) (v dvm.Variable, found bool) {
|
||||
func LoadSCValue(data_tree *Tree_Wrapper, scid crypto.Hash, key []byte) (v Variable, found bool) {
|
||||
//fmt.Printf("loading fromdb %s %s \n", scid, key)
|
||||
|
||||
object_data, err := data_tree.Get(key[:])
|
||||
@ -296,7 +329,7 @@ func (chain *Blockchain) LoadSCValue(data_tree *Tree_Wrapper, scid crypto.Hash,
|
||||
return v, true
|
||||
}
|
||||
|
||||
func (chain *Blockchain) LoadSCAssetValue(data_tree *Tree_Wrapper, scid crypto.Hash, asset crypto.Hash) (v uint64, found bool) {
|
||||
func LoadSCAssetValue(data_tree *Tree_Wrapper, scid crypto.Hash, asset crypto.Hash) (v uint64, found bool) {
|
||||
//fmt.Printf("loading fromdb %s %s \n", scid, key)
|
||||
|
||||
object_data, err := data_tree.Get(asset[:])
|
||||
@ -315,7 +348,7 @@ func (chain *Blockchain) LoadSCAssetValue(data_tree *Tree_Wrapper, scid crypto.H
|
||||
}
|
||||
|
||||
// reads a value from SC, always read balance
|
||||
func (chain *Blockchain) ReadSCValue(data_tree *Tree_Wrapper, scid crypto.Hash, key interface{}) (value interface{}) {
|
||||
func ReadSCValue(data_tree *Tree_Wrapper, scid crypto.Hash, key interface{}) (value interface{}) {
|
||||
var keybytes []byte
|
||||
|
||||
if key == nil {
|
||||
@ -323,22 +356,22 @@ func (chain *Blockchain) ReadSCValue(data_tree *Tree_Wrapper, scid crypto.Hash,
|
||||
}
|
||||
switch k := key.(type) {
|
||||
case uint64:
|
||||
keybytes = dvm.DataKey{Key: dvm.Variable{Type: dvm.Uint64, ValueUint64: k}}.MarshalBinaryPanic()
|
||||
keybytes = DataKey{Key: Variable{Type: Uint64, ValueUint64: k}}.MarshalBinaryPanic()
|
||||
case string:
|
||||
keybytes = dvm.DataKey{Key: dvm.Variable{Type: dvm.String, ValueString: k}}.MarshalBinaryPanic()
|
||||
keybytes = DataKey{Key: Variable{Type: String, ValueString: k}}.MarshalBinaryPanic()
|
||||
//case int64:
|
||||
// keybytes = dvm.DataKey{Key: dvm.Variable{Type: dvm.String, Value: k}}.MarshalBinaryPanic()
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
value_var, found := chain.LoadSCValue(data_tree, scid, keybytes)
|
||||
value_var, found := LoadSCValue(data_tree, scid, keybytes)
|
||||
//fmt.Printf("read value %+v", value_var)
|
||||
if found && value_var.Type != dvm.Invalid {
|
||||
if found && value_var.Type != Invalid {
|
||||
switch value_var.Type {
|
||||
case dvm.Uint64:
|
||||
case Uint64:
|
||||
value = value_var.ValueUint64
|
||||
case dvm.String:
|
||||
case String:
|
||||
value = value_var.ValueString
|
||||
default:
|
||||
panic("This variable cannot be loaded")
|
||||
@ -348,7 +381,7 @@ func (chain *Blockchain) ReadSCValue(data_tree *Tree_Wrapper, scid crypto.Hash,
|
||||
}
|
||||
|
||||
// store the value in the chain
|
||||
func (chain *Blockchain) StoreSCValue(data_tree *Tree_Wrapper, scid crypto.Hash, key, value []byte) {
|
||||
func StoreSCValue(data_tree *Tree_Wrapper, scid crypto.Hash, key, value []byte) {
|
||||
if bytes.Compare(scid[:], key) == 0 { // an scid can mint its assets infinitely
|
||||
return
|
||||
}
|
382
dvm/simulator.go
Normal file
382
dvm/simulator.go
Normal file
@ -0,0 +1,382 @@
|
||||
// Copyright 2017-2021 DERO Project. All rights reserved.
|
||||
// Use of this source code in any form is governed by RESEARCH license.
|
||||
// license can be found in the LICENSE file.
|
||||
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
|
||||
//
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package dvm
|
||||
|
||||
// this file implements necessary structure to SC handling
|
||||
|
||||
import "fmt"
|
||||
|
||||
//import "bytes"
|
||||
//import "runtime/debug"
|
||||
import "encoding/binary"
|
||||
import "time"
|
||||
import "math/big"
|
||||
import "math/rand"
|
||||
import "github.com/deroproject/derohe/cryptography/crypto"
|
||||
import "github.com/deroproject/derohe/cryptography/bn256"
|
||||
|
||||
import "golang.org/x/xerrors"
|
||||
import "github.com/deroproject/graviton"
|
||||
import "github.com/deroproject/derohe/rpc"
|
||||
import "github.com/deroproject/derohe/config"
|
||||
|
||||
//import "github.com/deroproject/derohe/transaction"
|
||||
|
||||
type Simulator struct {
|
||||
ss *graviton.Snapshot
|
||||
balance_tree *graviton.Tree
|
||||
sc_tree *graviton.Tree
|
||||
cache map[crypto.Hash]*graviton.Tree
|
||||
height uint64
|
||||
Balances map[string]map[string]uint64
|
||||
}
|
||||
|
||||
func SimulatorInitialize(ss *graviton.Snapshot) *Simulator {
|
||||
|
||||
var s Simulator
|
||||
var err error
|
||||
|
||||
if ss == nil {
|
||||
store, err := graviton.NewMemStore()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ss, err = store.LoadSnapshot(0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
s.ss = ss
|
||||
}
|
||||
s.ss = ss
|
||||
|
||||
s.balance_tree, err = ss.GetTree(config.BALANCE_TREE)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
s.sc_tree, err = ss.GetTree(config.SC_META)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
s.cache = map[crypto.Hash]*graviton.Tree{}
|
||||
s.Balances = map[string]map[string]uint64{}
|
||||
|
||||
//w_balance_tree := &dvm.Tree_Wrapper{Tree: balance_tree, Entries: map[string][]byte{}}
|
||||
//w_sc_tree := &dvm.Tree_Wrapper{Tree: sc_tree, Entries: map[string][]byte{}}
|
||||
|
||||
return &s
|
||||
}
|
||||
|
||||
// this is for testing some edge case in simulator
|
||||
func (s *Simulator) AccountAddBalance(addr rpc.Address, scid crypto.Hash, balance_value uint64) {
|
||||
balance := crypto.ConstructElGamal((*bn256.G1)(addr.PublicKey), crypto.ElGamal_BASE_G) // init zero balance
|
||||
nb := crypto.NonceBalance{NonceHeight: 0, Balance: balance}
|
||||
s.balance_tree.Put(addr.Compressed(), nb.Serialize())
|
||||
}
|
||||
|
||||
func (s *Simulator) SCInstall(sc_code string, incoming_values map[crypto.Hash]uint64, SCDATA rpc.Arguments, signer_addr *rpc.Address, fees uint64) (scid crypto.Hash, gascompute, gasstorage uint64, err error) {
|
||||
var blid crypto.Hash
|
||||
rand.Seed(time.Now().Unix())
|
||||
rand.Read(scid[:])
|
||||
rand.Read(blid[:])
|
||||
|
||||
var sc SmartContract
|
||||
if sc, _, err = ParseSmartContract(sc_code); err != nil {
|
||||
//logger.V(2).Error(err, "error Parsing sc", "txid", txhash, "pos", pos)
|
||||
return
|
||||
}
|
||||
|
||||
var meta SC_META_DATA
|
||||
if _, ok := sc.Functions["InitializePrivate"]; ok {
|
||||
meta.Type = 1
|
||||
}
|
||||
|
||||
w_sc_data_tree := Wrapped_tree(s.cache, s.ss, scid)
|
||||
w_sc_data_tree.Put(SC_Code_Key(scid), Variable{Type: String, ValueString: sc_code}.MarshalBinaryPanic())
|
||||
w_sc_tree := &Tree_Wrapper{Tree: s.sc_tree, Entries: map[string][]byte{}}
|
||||
w_sc_tree.Put(SC_Meta_Key(scid), meta.MarshalBinary())
|
||||
|
||||
entrypoint := "Initialize"
|
||||
if meta.Type == 1 { // if its a a private SC
|
||||
entrypoint = "InitializePrivate"
|
||||
}
|
||||
|
||||
gascompute, gasstorage, err = s.common(w_sc_tree, w_sc_data_tree, scid, s.height, s.height, uint64(time.Now().UnixMilli()), blid, scid, sc, entrypoint, 1, 0, signer_addr, incoming_values, SCDATA, fees, true)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Simulator) RunSC(incoming_values map[crypto.Hash]uint64, SCDATA rpc.Arguments, signer_addr *rpc.Address, fees uint64) (gascompute, gasstorage uint64, err error) {
|
||||
var blid, txid crypto.Hash
|
||||
rand.Read(blid[:])
|
||||
rand.Read(txid[:])
|
||||
|
||||
action_code := rpc.SC_ACTION(SCDATA.Value(rpc.SCACTION, rpc.DataUint64).(uint64))
|
||||
|
||||
switch action_code {
|
||||
case rpc.SC_INSTALL: // request to install an SC
|
||||
err = fmt.Errorf("cannot install code using this api")
|
||||
return
|
||||
|
||||
case rpc.SC_CALL: // trigger a CALL
|
||||
if !SCDATA.Has(rpc.SCID, rpc.DataHash) { // but only if it is present
|
||||
err = fmt.Errorf("no scid provided")
|
||||
return
|
||||
}
|
||||
if !SCDATA.Has("entrypoint", rpc.DataString) { // but only if it is present
|
||||
err = fmt.Errorf("no entrypoint provided")
|
||||
return
|
||||
}
|
||||
|
||||
scid := SCDATA.Value(rpc.SCID, rpc.DataHash).(crypto.Hash)
|
||||
|
||||
w_sc_tree := &Tree_Wrapper{Tree: s.sc_tree, Entries: map[string][]byte{}}
|
||||
if _, err = w_sc_tree.Get(SC_Meta_Key(scid)); err != nil {
|
||||
err = fmt.Errorf("scid %s not installed", scid)
|
||||
return
|
||||
}
|
||||
|
||||
w_sc_data_tree := Wrapped_tree(s.cache, s.ss, scid)
|
||||
entrypoint := SCDATA.Value("entrypoint", rpc.DataString).(string)
|
||||
balance, sc, _ := ReadSC(w_sc_tree, w_sc_data_tree, scid)
|
||||
|
||||
gascompute, gasstorage, err = s.common(w_sc_tree, w_sc_data_tree, scid, s.height, s.height, uint64(time.Now().UnixMilli()), blid, scid, sc, entrypoint, 1, balance, signer_addr, incoming_values, SCDATA, fees, true)
|
||||
return
|
||||
default:
|
||||
err = fmt.Errorf("unknown action_code code %d", action_code)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Simulator) common(w_sc_tree, w_sc_data_tree *Tree_Wrapper, scid crypto.Hash, bl_height, bl_topoheight, bl_timestamp uint64, blid crypto.Hash, txid crypto.Hash, sc SmartContract, entrypoint string, hard_fork_version_current int64, balance_at_start uint64, signer_addr *rpc.Address, incoming_values map[crypto.Hash]uint64, SCDATA rpc.Arguments, fees uint64, simulator bool) (gascompute, gasstorage uint64, err error) {
|
||||
|
||||
var signer [33]byte
|
||||
if signer_addr != nil {
|
||||
copy(signer[:], signer_addr.Compressed())
|
||||
}
|
||||
|
||||
gascompute, gasstorage, err = Execute_sc_function(w_sc_tree, w_sc_data_tree, scid, bl_height, bl_topoheight, uint64(time.Now().UnixMilli()), blid, scid, sc, entrypoint, 1, 0, signer, incoming_values, SCDATA, fees, simulator)
|
||||
fmt.Printf("sc execution error %s\n", err)
|
||||
|
||||
// we must commit all the changes
|
||||
// check whether we are not overflowing/underflowing, means SC is not over sending
|
||||
if err == nil {
|
||||
err = SanityCheckExternalTransfers(w_sc_data_tree, s.balance_tree, scid)
|
||||
}
|
||||
|
||||
if err != nil { // error occured, give everything to SC, since we may not have information to send them back
|
||||
var zeroaddress [33]byte
|
||||
if signer != zeroaddress { // if we can identify sender, return funds to him
|
||||
ErrorRevert(s.ss, s.cache, s.balance_tree, signer, scid, incoming_values)
|
||||
} else { // we could not extract signer, give burned funds to SC
|
||||
ErrorRevert(s.ss, s.cache, s.balance_tree, signer, scid, incoming_values)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
ProcessExternal(s.ss, s.cache, s.balance_tree, signer, scid, w_sc_data_tree, w_sc_tree)
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// this is core function used to evaluate when we are overflowing/underflowing
|
||||
func SanityCheckExternalTransfers(w_sc_data_tree *Tree_Wrapper, balance_tree *graviton.Tree, scid crypto.Hash) (err error) {
|
||||
total_per_asset := map[crypto.Hash]uint64{}
|
||||
for _, transfer := range w_sc_data_tree.Transfere { // do external tranfer
|
||||
if transfer.Amount == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// an SCID can generate it's token infinitely
|
||||
if transfer.Asset != scid && total_per_asset[transfer.Asset]+transfer.Amount <= total_per_asset[transfer.Asset] {
|
||||
err = fmt.Errorf("Balance calculation overflow")
|
||||
return
|
||||
} else {
|
||||
total_per_asset[transfer.Asset] = total_per_asset[transfer.Asset] + transfer.Amount
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
for asset, value := range total_per_asset {
|
||||
stored_value, _ := LoadSCAssetValue(w_sc_data_tree, scid, asset)
|
||||
// an SCID can generate it's token infinitely
|
||||
if asset != scid && stored_value-value > stored_value {
|
||||
err = fmt.Errorf("Balance calculation underflow stored_value %d transferring %d\n", stored_value, value)
|
||||
return
|
||||
}
|
||||
|
||||
var new_value [8]byte
|
||||
binary.BigEndian.PutUint64(new_value[:], stored_value-value)
|
||||
StoreSCValue(w_sc_data_tree, scid, asset[:], new_value[:])
|
||||
}
|
||||
}
|
||||
|
||||
//also check whether all destinations are registered
|
||||
if err == nil {
|
||||
for _, transfer := range w_sc_data_tree.Transfere {
|
||||
if _, err = balance_tree.Get([]byte(transfer.Address)); err == nil || xerrors.Is(err, graviton.ErrNotFound) {
|
||||
// everything is okay
|
||||
} else {
|
||||
err = fmt.Errorf("account is unregistered")
|
||||
//logger.V(1).Error(err, "account is unregistered", "txhash", txhash, "scid", scid, "address", transfer.Address)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// any error during this will panic
|
||||
func ErrorRevert(ss *graviton.Snapshot, cache map[crypto.Hash]*graviton.Tree, balance_tree *graviton.Tree, signer [33]byte, scid crypto.Hash, incoming_values map[crypto.Hash]uint64) {
|
||||
var err error
|
||||
|
||||
for scid_asset, burnvalue := range incoming_values {
|
||||
var zeroscid crypto.Hash
|
||||
|
||||
var curbtree *graviton.Tree
|
||||
switch scid_asset {
|
||||
case zeroscid: // main dero balance, handle it
|
||||
curbtree = balance_tree
|
||||
case scid: // this scid balance, handle it
|
||||
curbtree = cache[scid]
|
||||
default: // any other asset scid
|
||||
var ok bool
|
||||
if curbtree, ok = cache[scid_asset]; !ok {
|
||||
if curbtree, err = ss.GetTree(string(scid_asset[:])); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cache[scid_asset] = curbtree
|
||||
}
|
||||
}
|
||||
|
||||
if curbtree == nil {
|
||||
panic("tree cannot be nil at this point in time")
|
||||
}
|
||||
|
||||
if balance_serialized, err1 := curbtree.Get(signer[:]); err1 != nil { // no error can occur
|
||||
panic(err1) // only disk corruption can reach here
|
||||
} else {
|
||||
nb := new(crypto.NonceBalance).Deserialize(balance_serialized)
|
||||
nb.Balance = nb.Balance.Plus(new(big.Int).SetUint64(burnvalue)) // add back burn value to users balance homomorphically
|
||||
curbtree.Put(signer[:], nb.Serialize()) // reserialize and store
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ErrorDeposit(ss *graviton.Snapshot, cache map[crypto.Hash]*graviton.Tree, balance_tree *graviton.Tree, signer [33]byte, scid crypto.Hash, incoming_values map[crypto.Hash]uint64) {
|
||||
|
||||
for scid_asset, burnvalue := range incoming_values {
|
||||
var new_value [8]byte
|
||||
|
||||
w_sc_data_tree := Wrapped_tree(cache, ss, scid) // get a new tree, discarding everything
|
||||
|
||||
stored_value, _ := LoadSCAssetValue(w_sc_data_tree, scid, scid_asset)
|
||||
binary.BigEndian.PutUint64(new_value[:], stored_value+burnvalue)
|
||||
StoreSCValue(w_sc_data_tree, scid, scid_asset[:], new_value[:])
|
||||
|
||||
for k, v := range w_sc_data_tree.Entries { // commit incoming balances to tree
|
||||
if err := w_sc_data_tree.Tree.Put([]byte(k), v); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
cache[scid] = w_sc_data_tree.Tree
|
||||
}
|
||||
}
|
||||
|
||||
func ProcessExternal(ss *graviton.Snapshot, cache map[crypto.Hash]*graviton.Tree, balance_tree *graviton.Tree, signer [33]byte, scid crypto.Hash, w_sc_data_tree, w_sc_tree *Tree_Wrapper) {
|
||||
var err error
|
||||
|
||||
// anything below should never give error
|
||||
cache[scid] = w_sc_data_tree.Tree
|
||||
|
||||
for k, v := range w_sc_data_tree.Entries { // commit entire data to tree
|
||||
//if _, ok := globals.Arguments["--debug"]; ok && globals.Arguments["--debug"] != nil && chain.simulator {
|
||||
// logger.V(1).Info("Writing", "txid", txhash, "scid", scid, "key", fmt.Sprintf("%x", k), "value", fmt.Sprintf("%x", v))
|
||||
// }
|
||||
if len(v) == 0 {
|
||||
if err = w_sc_data_tree.Tree.Delete([]byte(k)); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
if err = w_sc_data_tree.Tree.Put([]byte(k), v); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range w_sc_tree.Entries {
|
||||
if err = w_sc_tree.Tree.Put([]byte(k), v); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
for i, transfer := range w_sc_data_tree.Transfere { // do external tranfer
|
||||
if transfer.Amount == 0 {
|
||||
continue
|
||||
}
|
||||
//fmt.Printf("%d sending to external %s %x\n", i,transfer.Asset,transfer.Address)
|
||||
var zeroscid crypto.Hash
|
||||
|
||||
var curbtree *graviton.Tree
|
||||
switch transfer.Asset {
|
||||
case zeroscid: // main dero balance, handle it
|
||||
curbtree = balance_tree
|
||||
case scid: // this scid balance, handle it
|
||||
curbtree = cache[scid]
|
||||
default: // any other asset scid
|
||||
var ok bool
|
||||
if curbtree, ok = cache[transfer.Asset]; !ok {
|
||||
if curbtree, err = ss.GetTree(string(transfer.Asset[:])); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cache[transfer.Asset] = curbtree
|
||||
}
|
||||
}
|
||||
|
||||
if curbtree == nil {
|
||||
panic("tree cannot be nil at this point in time")
|
||||
}
|
||||
|
||||
addr_bytes := []byte(transfer.Address)
|
||||
if _, err = balance_tree.Get(addr_bytes); err != nil { // first check whether address is registered
|
||||
err = fmt.Errorf("sending to non registered account acc %x err %s", addr_bytes, err) // this can only occur, if account no registered or dis corruption
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var balance_serialized []byte
|
||||
balance_serialized, err = curbtree.Get(addr_bytes)
|
||||
if err != nil && xerrors.Is(err, graviton.ErrNotFound) { // if the address is not found, lookup in main tree
|
||||
var p bn256.G1
|
||||
if err = p.DecodeCompressed(addr_bytes[:]); err != nil {
|
||||
panic(fmt.Errorf("key %x could not be decompressed", addr_bytes))
|
||||
}
|
||||
|
||||
balance := crypto.ConstructElGamal(&p, crypto.ElGamal_BASE_G) // init zero balance
|
||||
nb := crypto.NonceBalance{NonceHeight: 0, Balance: balance}
|
||||
balance_serialized = nb.Serialize()
|
||||
} else if err != nil {
|
||||
fmt.Printf("%s %d could not transfer %d %+v\n", scid, i, transfer.Amount, addr_bytes)
|
||||
panic(err) // only disk corruption can reach here
|
||||
}
|
||||
|
||||
nb := new(crypto.NonceBalance).Deserialize(balance_serialized)
|
||||
nb.Balance = nb.Balance.Plus(new(big.Int).SetUint64(transfer.Amount)) // add transfer to users balance homomorphically
|
||||
curbtree.Put(addr_bytes, nb.Serialize()) // reserialize and store
|
||||
}
|
||||
|
||||
}
|
174
dvm/simulator_test.go
Normal file
174
dvm/simulator_test.go
Normal file
@ -0,0 +1,174 @@
|
||||
// Copyright 2017-2018 DERO Project. All rights reserved.
|
||||
// Use of this source code in any form is governed by RESEARCH license.
|
||||
// license can be found in the LICENSE file.
|
||||
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
|
||||
//
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package dvm
|
||||
|
||||
//import "fmt"
|
||||
//import "reflect"
|
||||
import "strings"
|
||||
import "testing"
|
||||
|
||||
import "github.com/deroproject/derohe/rpc"
|
||||
import "github.com/deroproject/derohe/cryptography/crypto"
|
||||
|
||||
var sc = `/* Lottery Smart Contract Example in DVM-BASIC.
|
||||
This lottery smart contract will give lottery wins on every second try in following default contract.
|
||||
Make depost transaction to this SCID to play lottery.
|
||||
Check https://github.com/deroproject/derohe/blob/main/guide/examples/lottery_sc_guide.md
|
||||
*/
|
||||
|
||||
|
||||
|
||||
Function Lottery() Uint64
|
||||
10 dim deposit_count,winner as Uint64
|
||||
20 LET deposit_count = LOAD("deposit_count")+1
|
||||
25 IF DEROVALUE() == 0 THEN GOTO 110 // if deposit amount is 0, simply return
|
||||
30 STORE("depositor_address" + (deposit_count-1), SIGNER()) // store address for later on payment
|
||||
40 STORE("deposit_total", LOAD("deposit_total") + DEROVALUE() )
|
||||
50 STORE("deposit_count",deposit_count)
|
||||
60 IF LOAD("lotteryeveryXdeposit") > deposit_count THEN GOTO 110 // we will wait till X players join in
|
||||
// we are here means all players have joined in, roll the DICE,
|
||||
70 LET winner = RANDOM() % deposit_count // we have a winner
|
||||
80 SEND_DERO_TO_ADDRESS(LOAD("depositor_address" + winner) , LOAD("lotterygiveback")*LOAD("deposit_total")/10000)
|
||||
// Re-Initialize for another round
|
||||
90 STORE("deposit_count", 0) // initial players
|
||||
100 STORE("deposit_total", 0) // total deposit of all players
|
||||
110 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
// This function is used to initialize parameters during install time
|
||||
Function Initialize() Uint64
|
||||
5 version("1.2.3")
|
||||
10 STORE("owner", SIGNER()) // store in DB ["owner"] = address
|
||||
20 STORE("lotteryeveryXdeposit", 2) // lottery will reward every X deposits
|
||||
// How much will lottery giveback in 1/10000 parts, granularity .01 %
|
||||
30 STORE("lotterygiveback", 9900) // lottery will give reward 99% of deposits, 1 % is accumulated for owner to withdraw
|
||||
33 STORE("deposit_count", 0) // initial players
|
||||
34 STORE("deposit_total", 0) // total deposit of all players
|
||||
// 35 printf "Initialize executed"
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
// Function to tune lottery parameters
|
||||
Function TuneLotteryParameters(input Uint64, lotteryeveryXdeposit Uint64, lotterygiveback Uint64) Uint64
|
||||
10 dim key,stored_owner as String
|
||||
20 dim value_uint64 as Uint64
|
||||
30 IF LOAD("owner") == SIGNER() THEN GOTO 100 // check whether owner is real owner
|
||||
40 RETURN 1
|
||||
|
||||
100 STORE("lotteryeveryXdeposit", lotteryeveryXdeposit) // lottery will reward every X deposits
|
||||
130 STORE("lotterygiveback", value_uint64) // how much will lottery giveback in 1/10000 parts, granularity .01 %
|
||||
140 RETURN 0 // return success
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
// This function is used to change owner
|
||||
// owner is an string form of address
|
||||
Function TransferOwnership(newowner String) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 STORE("tmpowner",ADDRESS_RAW(newowner))
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// Until the new owner claims ownership, existing owner remains owner
|
||||
Function ClaimOwnership() Uint64
|
||||
10 IF LOAD("tmpowner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 STORE("owner",SIGNER()) // ownership claim successful
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// If signer is owner, withdraw any requested funds
|
||||
// If everthing is okay, they will be showing in signers wallet
|
||||
Function Withdraw( amount Uint64) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 SEND_DERO_TO_ADDRESS(SIGNER(),amount)
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// If signer is owner, provide him rights to update code anytime
|
||||
// make sure update is always available to SC
|
||||
Function UpdateCode( code String) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 UPDATE_SC_CODE(code)
|
||||
40 RETURN 0
|
||||
End Function
|
||||
`
|
||||
|
||||
// run the test
|
||||
func Test_Simulator_execution(t *testing.T) {
|
||||
s := SimulatorInitialize(nil)
|
||||
var addr *rpc.Address
|
||||
var err error
|
||||
|
||||
if addr, err = rpc.NewAddress(strings.TrimSpace("deto1qy0ehnqjpr0wxqnknyc66du2fsxyktppkr8m8e6jvplp954klfjz2qqdzcd8p")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var zerohash crypto.Hash
|
||||
|
||||
s.AccountAddBalance(*addr, zerohash, 500)
|
||||
scid, gascompute, gasstorage, err := s.SCInstall(sc, map[crypto.Hash]uint64{}, rpc.Arguments{}, addr, 0)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("cannot install contract %s\n", err)
|
||||
}
|
||||
_ = gascompute
|
||||
_ = gasstorage
|
||||
|
||||
// trigger first time lottery play
|
||||
gascompute, gasstorage, err = s.RunSC(map[crypto.Hash]uint64{zerohash: 45}, rpc.Arguments{{rpc.SCACTION, rpc.DataUint64, uint64(rpc.SC_CALL)}, {rpc.SCID, rpc.DataHash, scid}, rpc.Argument{"entrypoint", rpc.DataString, "Lottery"}}, addr, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot run contract %s\n", err)
|
||||
}
|
||||
|
||||
w_sc_data_tree := Wrapped_tree(s.cache, s.ss, scid)
|
||||
stored_value, _ := LoadSCAssetValue(w_sc_data_tree, scid, zerohash)
|
||||
|
||||
if 45 != stored_value {
|
||||
t.Fatalf("storage corruption dero value")
|
||||
}
|
||||
|
||||
if uint64(45) != ReadSCValue(w_sc_data_tree, scid, "deposit_total") {
|
||||
t.Fatalf("storage corruption")
|
||||
}
|
||||
|
||||
// trigger second time lottery play
|
||||
gascompute, gasstorage, err = s.RunSC(map[crypto.Hash]uint64{zerohash: 55}, rpc.Arguments{{rpc.SCACTION, rpc.DataUint64, uint64(rpc.SC_CALL)}, {rpc.SCID, rpc.DataHash, scid}, rpc.Argument{"entrypoint", rpc.DataString, "Lottery"}}, addr, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot run contract %s\n", err)
|
||||
}
|
||||
|
||||
w_sc_data_tree = Wrapped_tree(s.cache, s.ss, scid)
|
||||
|
||||
// only 1 is left ( which is profit)
|
||||
if stored_value, _ = LoadSCAssetValue(w_sc_data_tree, scid, zerohash); 1 != stored_value {
|
||||
t.Fatalf("storage corruption dero value")
|
||||
}
|
||||
|
||||
// total deposit must be zero
|
||||
if uint64(0) != ReadSCValue(w_sc_data_tree, scid, "deposit_total") {
|
||||
t.Fatalf("storage corruption")
|
||||
}
|
||||
|
||||
}
|
@ -217,6 +217,7 @@ type (
|
||||
ValidBlock string `json:"valid_block"` // TX is valid in this block
|
||||
InvalidBlock []string `json:"invalid_block"` // TX is invalid in this block, 0 or more
|
||||
Ring [][]string `json:"ring"` // ring members completed, since tx contains compressed
|
||||
Signer string `json:"signer"` // if signer could be extracted, it will be placed here
|
||||
Balance uint64 `json:"balance"` // if tx is SC, give SC balance at start
|
||||
Code string `json:"code"` // smart contract code at start
|
||||
BalanceNow uint64 `json:"balancenow"` // if tx is SC, give SC balance at current topo height
|
||||
@ -269,27 +270,6 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
/*
|
||||
{
|
||||
"id": "0",
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"alt_blocks_count": 5,
|
||||
"difficulty": 972165250,
|
||||
"grey_peerlist_size": 2280,
|
||||
"height": 993145,
|
||||
"incoming_connections_count": 0,
|
||||
"outgoing_connections_count": 8,
|
||||
"status": "OK",
|
||||
"target": 60,
|
||||
"target_height": 993137,
|
||||
"testnet": false,
|
||||
"top_block_hash": "",
|
||||
"tx_count": 564287,
|
||||
"tx_pool_size": 45,
|
||||
"white_peerlist_size": 529
|
||||
}
|
||||
}*/
|
||||
type (
|
||||
GetInfo_Params struct{} // no params
|
||||
GetInfo_Result struct {
|
||||
@ -319,3 +299,10 @@ type (
|
||||
Status string `json:"status"`
|
||||
}
|
||||
)
|
||||
|
||||
type GasEstimate_Params Transfer_Params // same structure as used by transfer call
|
||||
type GasEstimate_Result struct {
|
||||
GasCompute uint64 `json:"gascompute"`
|
||||
GasStorage uint64 `json:"gasstorage"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
@ -205,6 +205,8 @@ type (
|
||||
SC_ID string `json:"scid"`
|
||||
SC_RPC Arguments `json:"sc_rpc"`
|
||||
Ringsize uint64 `json:"ringsize"`
|
||||
Fees uint64 `json:"fees"`
|
||||
Signer string `json:"signer"` // only used for gas estimation
|
||||
}
|
||||
Transfer_Result struct {
|
||||
TXID string `json:"txid,omitempty"`
|
||||
|
103
run_integration_test.sh
Executable file
103
run_integration_test.sh
Executable file
@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
CURDIR=`/bin/pwd`
|
||||
BASEDIR=$(dirname $0)
|
||||
ABSPATH=$(readlink -f $0)
|
||||
ABSDIR=$(dirname $ABSPATH)
|
||||
|
||||
|
||||
# set -x # to enable debug and verbose printing of each and every command
|
||||
_DEBUG="on"
|
||||
function DEBUG()
|
||||
{
|
||||
[ "$_DEBUG" == "on" ] && $@
|
||||
}
|
||||
|
||||
|
||||
function check_errs()
|
||||
{
|
||||
# Function. Parameter 1 is the return code
|
||||
# Para. 2 is text to display on failure.
|
||||
|
||||
if [ "${1}" -ne "0" ]; then
|
||||
echo "ERROR # ${1} : ${2}"
|
||||
|
||||
# if [ "$#" -eq "3"]; then
|
||||
echo "logs "
|
||||
cat /dev/shm/dtest/log.txt
|
||||
# cat "${3}"
|
||||
# fi
|
||||
# as a bonus, make our script exit with the right error code.
|
||||
# rm -rf /dev/shm/dtest >/dev/null 2>&1
|
||||
killall -9 simulator >/dev/null 2>&1
|
||||
exit ${1}
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
function run_single_test()
|
||||
{
|
||||
test=${1}
|
||||
killall -9 simulator >/dev/null 2>&1
|
||||
rm -rf /dev/shm/dtest >/dev/null 2>&1
|
||||
mkdir /dev/shm/dtest
|
||||
cd /dev/shm/dtest
|
||||
|
||||
/tmp/simulator --clog-level 2 $disableautomine >/dev/shm/dtest/dero.log 2>&1 &
|
||||
disown
|
||||
check_errs $? "Could not run simulator"
|
||||
echo "Simulator started"
|
||||
sleep 4
|
||||
|
||||
DEBUG echo "running test $test"
|
||||
rm /dev/shm/dtest/log.txt >/dev/null 2>&1
|
||||
rm /dev/shm/dtest/log.txt >/dev/null 2>&1
|
||||
|
||||
cd $test
|
||||
$test/run_test.sh >/dev/shm/dtest/log.txt 2>&1
|
||||
|
||||
check_errs $? "test failed $test"
|
||||
killall -9 simulator >/dev/null 2>&1
|
||||
cd $CURDIR
|
||||
}
|
||||
|
||||
function run_tests()
|
||||
{
|
||||
tests=$(find ${1} -mindepth 1 -maxdepth 1 -type d)
|
||||
for test in $tests; do
|
||||
run_single_test "$test"
|
||||
done
|
||||
}
|
||||
|
||||
cd $ABSDIR
|
||||
go build -o /tmp/ ./cmd/...
|
||||
check_errs $? "Could not build binaries"
|
||||
cd $CURDIR
|
||||
|
||||
|
||||
|
||||
if [[ $# -eq 1 ]]; then # if user requsted single test
|
||||
|
||||
if [ -d "$ABSDIR/tests/normal/${1}" ]; then
|
||||
run_single_test "$ABSDIR/tests/normal/${1}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -d "$ABSDIR/tests/specific/${1}" ]; then
|
||||
disableautomine="--noautomine"
|
||||
run_single_test "$ABSDIR/tests/specific/${1}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "no such test found ${1}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
#we will first run specific/special test cases
|
||||
disableautomine="--noautomine"
|
||||
run_tests $ABSDIR/tests/specific
|
||||
|
||||
#we will first run normal test cases
|
||||
disableautomine=""
|
||||
run_tests $ABSDIR/tests/normal
|
||||
|
58
tests/normal/gasestimate_installsc_test/run_test.sh
Executable file
58
tests/normal/gasestimate_installsc_test/run_test.sh
Executable file
@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#set -x # to enable debug and verbose printing of each and every command
|
||||
|
||||
CURDIR=`/bin/pwd`
|
||||
BASEDIR=$(dirname $0)
|
||||
ABSPATH=$(readlink -f $0)
|
||||
ABSDIR=$(dirname $ABSPATH)
|
||||
|
||||
|
||||
command -v curl >/dev/null 2>&1 || { echo "I require curl but it's not installed. Aborting." >&2; exit 1; }
|
||||
command -v jq >/dev/null 2>&1 || { echo "I require jq but it's not installed. Aborting." >&2; exit 1; }
|
||||
command -v base64 >/dev/null 2>&1 || { echo "I require base64 but it's not installed. Aborting." >&2; exit 1; }
|
||||
|
||||
|
||||
daemon_rpc_port="20000" # daemon rpc is listening on this port
|
||||
|
||||
# we have number of wallets listening at ports from 30000
|
||||
# we will be using 3 wallets, named owner, player1,player2
|
||||
owner_rpc_port="30000"
|
||||
player1_rpc_port="30001"
|
||||
player2_rpc_port="30002"
|
||||
|
||||
owner_address=$(curl --silent http://127.0.0.1:$owner_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
player1_address=$(curl --silent http://127.0.0.1:$player1_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
player2_address=$(curl --silent http://127.0.0.1:$player2_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
|
||||
|
||||
function balance(){
|
||||
curl --silent http://127.0.0.1:$1/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getbalance"}' -H 'Content-Type: application/json'| jq -r ".result.balance"
|
||||
}
|
||||
|
||||
function scbalance(){
|
||||
curl --silent http://127.0.0.1:$daemon_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getsc","params":{ "scid":"'"$1"'" , "code":false, "keysstring":["deposit_count"]}}' -H 'Content-Type: application/json' | jq -r ".result.balance"
|
||||
}
|
||||
|
||||
echo "SC owner address" $owner_address
|
||||
echo "player1 address" $player1_address
|
||||
echo "player2 address" $player2_address
|
||||
|
||||
|
||||
# use owner wallet to load/install an lotter sc to chain
|
||||
#scid=$(curl --silent --request POST --data-binary @test.bas http://127.0.0.1:$owner_rpc_port/install_sc| jq -r ".txid")
|
||||
#echo "SCID" $scid
|
||||
#sleep 1
|
||||
|
||||
|
||||
gas=`curl --silent http://127.0.0.1:$daemon_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getgasestimate","params":{ "transfers":[{"amount":100000,"destination":"deto1qxsz7v707t8mla4mslptlf6w7zkgrukvg5wfna0tha48yfjcahwh64qxnus7f"}], "sc":"'$(base64 -w 0 test.bas)'" }}' -H 'Content-Type: application/json' | jq -r ".result.gasstorage"`
|
||||
|
||||
|
||||
|
||||
|
||||
if [[ $gas -gt 10 ]]
|
||||
then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
93
tests/normal/gasestimate_installsc_test/test.bas
Normal file
93
tests/normal/gasestimate_installsc_test/test.bas
Normal file
@ -0,0 +1,93 @@
|
||||
/* Lottery Smart Contract Example in DVM-BASIC.
|
||||
This lottery smart contract will give lottery wins on every second try in following default contract.
|
||||
Make depost transaction to this SCID to play lottery.
|
||||
Check https://github.com/deroproject/derohe/blob/main/guide/examples/lottery_sc_guide.md
|
||||
*/
|
||||
|
||||
|
||||
|
||||
Function Lottery() Uint64
|
||||
10 dim deposit_count,winner as Uint64
|
||||
20 LET deposit_count = LOAD("deposit_count")+1
|
||||
25 IF DEROVALUE() == 0 THEN GOTO 110 // if deposit amount is 0, simply return
|
||||
30 STORE("depositor_address" + (deposit_count-1), SIGNER()) // store address for later on payment
|
||||
40 STORE("deposit_total", LOAD("deposit_total") + DEROVALUE() )
|
||||
50 STORE("deposit_count",deposit_count)
|
||||
60 IF LOAD("lotteryeveryXdeposit") > deposit_count THEN GOTO 110 // we will wait till X players join in
|
||||
// we are here means all players have joined in, roll the DICE,
|
||||
70 LET winner = RANDOM() % deposit_count // we have a winner
|
||||
80 SEND_DERO_TO_ADDRESS(LOAD("depositor_address" + winner) , LOAD("lotterygiveback")*LOAD("deposit_total")/10000)
|
||||
// Re-Initialize for another round
|
||||
90 STORE("deposit_count", 0) // initial players
|
||||
100 STORE("deposit_total", 0) // total deposit of all players
|
||||
110 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
// This function is used to initialize parameters during install time
|
||||
Function Initialize() Uint64
|
||||
5 version("1.2.3")
|
||||
10 STORE("owner", SIGNER()) // store in DB ["owner"] = address
|
||||
20 STORE("lotteryeveryXdeposit", 2) // lottery will reward every X deposits
|
||||
// How much will lottery giveback in 1/10000 parts, granularity .01 %
|
||||
30 STORE("lotterygiveback", 9900) // lottery will give reward 99% of deposits, 1 % is accumulated for owner to withdraw
|
||||
33 STORE("deposit_count", 0) // initial players
|
||||
34 STORE("deposit_total", 0) // total deposit of all players
|
||||
// 35 printf "Initialize executed"
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
// Function to tune lottery parameters
|
||||
Function TuneLotteryParameters(input Uint64, lotteryeveryXdeposit Uint64, lotterygiveback Uint64) Uint64
|
||||
10 dim key,stored_owner as String
|
||||
20 dim value_uint64 as Uint64
|
||||
30 IF LOAD("owner") == SIGNER() THEN GOTO 100 // check whether owner is real owner
|
||||
40 RETURN 1
|
||||
|
||||
100 STORE("lotteryeveryXdeposit", lotteryeveryXdeposit) // lottery will reward every X deposits
|
||||
130 STORE("lotterygiveback", value_uint64) // how much will lottery giveback in 1/10000 parts, granularity .01 %
|
||||
140 RETURN 0 // return success
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
// This function is used to change owner
|
||||
// owner is an string form of address
|
||||
Function TransferOwnership(newowner String) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 STORE("tmpowner",ADDRESS_RAW(newowner))
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// Until the new owner claims ownership, existing owner remains owner
|
||||
Function ClaimOwnership() Uint64
|
||||
10 IF LOAD("tmpowner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 STORE("owner",SIGNER()) // ownership claim successful
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// If signer is owner, withdraw any requested funds
|
||||
// If everthing is okay, they will be showing in signers wallet
|
||||
Function Withdraw( amount Uint64) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 SEND_DERO_TO_ADDRESS(SIGNER(),amount)
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// If signer is owner, provide him rights to update code anytime
|
||||
// make sure update is always available to SC
|
||||
Function UpdateCode( code String) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 UPDATE_SC_CODE(code)
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
|
58
tests/normal/gasestimate_runsc_test/run_test.sh
Executable file
58
tests/normal/gasestimate_runsc_test/run_test.sh
Executable file
@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#set -x # to enable debug and verbose printing of each and every command
|
||||
|
||||
CURDIR=`/bin/pwd`
|
||||
BASEDIR=$(dirname $0)
|
||||
ABSPATH=$(readlink -f $0)
|
||||
ABSDIR=$(dirname $ABSPATH)
|
||||
|
||||
|
||||
command -v curl >/dev/null 2>&1 || { echo "I require curl but it's not installed. Aborting." >&2; exit 1; }
|
||||
command -v jq >/dev/null 2>&1 || { echo "I require jq but it's not installed. Aborting." >&2; exit 1; }
|
||||
command -v base64 >/dev/null 2>&1 || { echo "I require base64 but it's not installed. Aborting." >&2; exit 1; }
|
||||
|
||||
|
||||
daemon_rpc_port="20000" # daemon rpc is listening on this port
|
||||
|
||||
# we have number of wallets listening at ports from 30000
|
||||
# we will be using 3 wallets, named owner, player1,player2
|
||||
owner_rpc_port="30000"
|
||||
player1_rpc_port="30001"
|
||||
player2_rpc_port="30002"
|
||||
|
||||
owner_address=$(curl --silent http://127.0.0.1:$owner_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
player1_address=$(curl --silent http://127.0.0.1:$player1_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
player2_address=$(curl --silent http://127.0.0.1:$player2_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
|
||||
|
||||
function balance(){
|
||||
curl --silent http://127.0.0.1:$1/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getbalance"}' -H 'Content-Type: application/json'| jq -r ".result.balance"
|
||||
}
|
||||
|
||||
function scbalance(){
|
||||
curl --silent http://127.0.0.1:$daemon_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getsc","params":{ "scid":"'"$1"'" , "code":false, "keysstring":["deposit_count"]}}' -H 'Content-Type: application/json' | jq -r ".result.balance"
|
||||
}
|
||||
|
||||
echo "SC owner address" $owner_address
|
||||
echo "player1 address" $player1_address
|
||||
echo "player2 address" $player2_address
|
||||
|
||||
|
||||
# use owner wallet to load/install an lotter sc to chain
|
||||
scid=$(curl --silent --request POST --data-binary @test.bas http://127.0.0.1:$owner_rpc_port/install_sc| jq -r ".txid")
|
||||
echo "SCID" $scid
|
||||
sleep 3
|
||||
|
||||
|
||||
gasstorage=$(curl --silent http://127.0.0.1:$daemon_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getgasestimate","params":{ "transfers":[{"amount":100000,"destination":"deto1qxsz7v707t8mla4mslptlf6w7zkgrukvg5wfna0tha48yfjcahwh64qxnus7f"}], "sc_rpc":[{"name":"SC_ID","datatype":"H","value":"'"$scid"'"}, {"name":"SC_ACTION","datatype":"U","value":0},{"name":"entrypoint","datatype":"S","value":"Lottery"}] }}' -H 'Content-Type: application/json' | jq -r ".result.gasstorage")
|
||||
|
||||
|
||||
|
||||
|
||||
if [[ $gasstorage -gt 50 ]]
|
||||
then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
93
tests/normal/gasestimate_runsc_test/test.bas
Normal file
93
tests/normal/gasestimate_runsc_test/test.bas
Normal file
@ -0,0 +1,93 @@
|
||||
/* Lottery Smart Contract Example in DVM-BASIC.
|
||||
This lottery smart contract will give lottery wins on every second try in following default contract.
|
||||
Make depost transaction to this SCID to play lottery.
|
||||
Check https://github.com/deroproject/derohe/blob/main/guide/examples/lottery_sc_guide.md
|
||||
*/
|
||||
|
||||
|
||||
|
||||
Function Lottery() Uint64
|
||||
10 dim deposit_count,winner as Uint64
|
||||
20 LET deposit_count = LOAD("deposit_count")+1
|
||||
25 IF DEROVALUE() == 0 THEN GOTO 110 // if deposit amount is 0, simply return
|
||||
30 STORE("depositor_address" + (deposit_count-1), SIGNER()) // store address for later on payment
|
||||
40 STORE("deposit_total", LOAD("deposit_total") + DEROVALUE() )
|
||||
50 STORE("deposit_count",deposit_count)
|
||||
60 IF LOAD("lotteryeveryXdeposit") > deposit_count THEN GOTO 110 // we will wait till X players join in
|
||||
// we are here means all players have joined in, roll the DICE,
|
||||
70 LET winner = RANDOM() % deposit_count // we have a winner
|
||||
80 SEND_DERO_TO_ADDRESS(LOAD("depositor_address" + winner) , LOAD("lotterygiveback")*LOAD("deposit_total")/10000)
|
||||
// Re-Initialize for another round
|
||||
90 STORE("deposit_count", 0) // initial players
|
||||
100 STORE("deposit_total", 0) // total deposit of all players
|
||||
110 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
// This function is used to initialize parameters during install time
|
||||
Function Initialize() Uint64
|
||||
5 version("1.2.3")
|
||||
10 STORE("owner", SIGNER()) // store in DB ["owner"] = address
|
||||
20 STORE("lotteryeveryXdeposit", 2) // lottery will reward every X deposits
|
||||
// How much will lottery giveback in 1/10000 parts, granularity .01 %
|
||||
30 STORE("lotterygiveback", 9900) // lottery will give reward 99% of deposits, 1 % is accumulated for owner to withdraw
|
||||
33 STORE("deposit_count", 0) // initial players
|
||||
34 STORE("deposit_total", 0) // total deposit of all players
|
||||
// 35 printf "Initialize executed"
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
// Function to tune lottery parameters
|
||||
Function TuneLotteryParameters(input Uint64, lotteryeveryXdeposit Uint64, lotterygiveback Uint64) Uint64
|
||||
10 dim key,stored_owner as String
|
||||
20 dim value_uint64 as Uint64
|
||||
30 IF LOAD("owner") == SIGNER() THEN GOTO 100 // check whether owner is real owner
|
||||
40 RETURN 1
|
||||
|
||||
100 STORE("lotteryeveryXdeposit", lotteryeveryXdeposit) // lottery will reward every X deposits
|
||||
130 STORE("lotterygiveback", value_uint64) // how much will lottery giveback in 1/10000 parts, granularity .01 %
|
||||
140 RETURN 0 // return success
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
// This function is used to change owner
|
||||
// owner is an string form of address
|
||||
Function TransferOwnership(newowner String) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 STORE("tmpowner",ADDRESS_RAW(newowner))
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// Until the new owner claims ownership, existing owner remains owner
|
||||
Function ClaimOwnership() Uint64
|
||||
10 IF LOAD("tmpowner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 STORE("owner",SIGNER()) // ownership claim successful
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// If signer is owner, withdraw any requested funds
|
||||
// If everthing is okay, they will be showing in signers wallet
|
||||
Function Withdraw( amount Uint64) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 SEND_DERO_TO_ADDRESS(SIGNER(),amount)
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// If signer is owner, provide him rights to update code anytime
|
||||
// make sure update is always available to SC
|
||||
Function UpdateCode( code String) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 UPDATE_SC_CODE(code)
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
|
68
tests/normal/lottery_test/run_test.sh
Executable file
68
tests/normal/lottery_test/run_test.sh
Executable file
@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#set -x # to enable debug and verbose printing of each and every command
|
||||
|
||||
CURDIR=`/bin/pwd`
|
||||
BASEDIR=$(dirname $0)
|
||||
ABSPATH=$(readlink -f $0)
|
||||
ABSDIR=$(dirname $ABSPATH)
|
||||
|
||||
|
||||
command -v curl >/dev/null 2>&1 || { echo "I require curl but it's not installed. Aborting." >&2; exit 1; }
|
||||
command -v jq >/dev/null 2>&1 || { echo "I require jq but it's not installed. Aborting." >&2; exit 1; }
|
||||
|
||||
|
||||
daemon_rpc_port="20000" # daemon rpc is listening on this port
|
||||
|
||||
# we have number of wallets listening at ports from 30000
|
||||
# we will be using 3 wallets, named owner, player1,player2
|
||||
owner_rpc_port="30000"
|
||||
player1_rpc_port="30001"
|
||||
player2_rpc_port="30002"
|
||||
|
||||
owner_address=$(curl --silent http://127.0.0.1:$owner_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
player1_address=$(curl --silent http://127.0.0.1:$player1_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
player2_address=$(curl --silent http://127.0.0.1:$player2_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
|
||||
|
||||
function balance(){
|
||||
curl --silent http://127.0.0.1:$1/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getbalance"}' -H 'Content-Type: application/json'| jq -r ".result.balance"
|
||||
}
|
||||
|
||||
function scbalance(){
|
||||
curl --silent http://127.0.0.1:$daemon_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getsc","params":{ "scid":"'"$1"'" , "code":false, "keysstring":["deposit_count"]}}' -H 'Content-Type: application/json' | jq -r ".result.balance"
|
||||
}
|
||||
|
||||
echo "SC owner address" $owner_address
|
||||
echo "player1 address" $player1_address
|
||||
echo "player2 address" $player2_address
|
||||
|
||||
|
||||
# use owner wallet to load/install an lotter sc to chain
|
||||
scid=$(curl --silent --request POST --data-binary @test.bas http://127.0.0.1:$owner_rpc_port/install_sc| jq -r ".txid")
|
||||
echo "SCID" $scid
|
||||
sleep 1
|
||||
|
||||
|
||||
#curl --silent http://127.0.0.1:$daemon_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getsc","params":{ "scid":"'"$scid"'" , "code":false, "keysstring":["deposit_count"]}}' -H 'Content-Type: application/json'
|
||||
|
||||
echo -n "Player 1 play txid "
|
||||
curl --silent http://127.0.0.1:$player1_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"scinvoke","params":{"sc_dero_deposit":3000,"scid":"'"$scid"'","ringsize":2, "sc_rpc":[{"name":"entrypoint","datatype":"S","value":"Lottery"}] }}' -H 'Content-Type: application/json' | jq -r ".result.txid"
|
||||
echo -n "Player 2 play txid "
|
||||
curl --silent http://127.0.0.1:$player2_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"scinvoke","params":{"sc_dero_deposit":3000,"scid":"'"$scid"'","ringsize":2, "sc_rpc":[{"name":"entrypoint","datatype":"S","value":"Lottery"}] }}' -H 'Content-Type: application/json' | jq -r ".result.txid"
|
||||
sleep 2
|
||||
|
||||
curl --silent http://127.0.0.1:$daemon_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getsc","params":{ "scid":"'"$scid"'" , "code":false, "keysstring":["deposit_count"]}}' -H 'Content-Type: application/json' | jq -r ".result.balance"
|
||||
|
||||
|
||||
echo "SC balance" $(scbalance $scid)
|
||||
echo "SC owner balance" $(balance $owner_rpc_port)
|
||||
echo "SC player1 balance" $(balance $player1_rpc_port)
|
||||
echo "SC player2 balance" $(balance $player2_rpc_port)
|
||||
|
||||
if [[ $(balance $player1_rpc_port) -gt 800000 || $(balance $player2_rpc_port) -gt 800000 ]]
|
||||
then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
93
tests/normal/lottery_test/test.bas
Normal file
93
tests/normal/lottery_test/test.bas
Normal file
@ -0,0 +1,93 @@
|
||||
/* Lottery Smart Contract Example in DVM-BASIC.
|
||||
This lottery smart contract will give lottery wins on every second try in following default contract.
|
||||
Make depost transaction to this SCID to play lottery.
|
||||
Check https://github.com/deroproject/derohe/blob/main/guide/examples/lottery_sc_guide.md
|
||||
*/
|
||||
|
||||
|
||||
|
||||
Function Lottery() Uint64
|
||||
10 dim deposit_count,winner as Uint64
|
||||
20 LET deposit_count = LOAD("deposit_count")+1
|
||||
25 IF DEROVALUE() == 0 THEN GOTO 110 // if deposit amount is 0, simply return
|
||||
30 STORE("depositor_address" + (deposit_count-1), SIGNER()) // store address for later on payment
|
||||
40 STORE("deposit_total", LOAD("deposit_total") + DEROVALUE() )
|
||||
50 STORE("deposit_count",deposit_count)
|
||||
60 IF LOAD("lotteryeveryXdeposit") > deposit_count THEN GOTO 110 // we will wait till X players join in
|
||||
// we are here means all players have joined in, roll the DICE,
|
||||
70 LET winner = RANDOM() % deposit_count // we have a winner
|
||||
80 SEND_DERO_TO_ADDRESS(LOAD("depositor_address" + winner) , LOAD("lotterygiveback")*LOAD("deposit_total")/10000)
|
||||
// Re-Initialize for another round
|
||||
90 STORE("deposit_count", 0) // initial players
|
||||
100 STORE("deposit_total", 0) // total deposit of all players
|
||||
110 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
// This function is used to initialize parameters during install time
|
||||
Function Initialize() Uint64
|
||||
5 version("1.2.3")
|
||||
10 STORE("owner", SIGNER()) // store in DB ["owner"] = address
|
||||
20 STORE("lotteryeveryXdeposit", 2) // lottery will reward every X deposits
|
||||
// How much will lottery giveback in 1/10000 parts, granularity .01 %
|
||||
30 STORE("lotterygiveback", 9900) // lottery will give reward 99% of deposits, 1 % is accumulated for owner to withdraw
|
||||
33 STORE("deposit_count", 0) // initial players
|
||||
34 STORE("deposit_total", 0) // total deposit of all players
|
||||
// 35 printf "Initialize executed"
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
// Function to tune lottery parameters
|
||||
Function TuneLotteryParameters(input Uint64, lotteryeveryXdeposit Uint64, lotterygiveback Uint64) Uint64
|
||||
10 dim key,stored_owner as String
|
||||
20 dim value_uint64 as Uint64
|
||||
30 IF LOAD("owner") == SIGNER() THEN GOTO 100 // check whether owner is real owner
|
||||
40 RETURN 1
|
||||
|
||||
100 STORE("lotteryeveryXdeposit", lotteryeveryXdeposit) // lottery will reward every X deposits
|
||||
130 STORE("lotterygiveback", value_uint64) // how much will lottery giveback in 1/10000 parts, granularity .01 %
|
||||
140 RETURN 0 // return success
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
// This function is used to change owner
|
||||
// owner is an string form of address
|
||||
Function TransferOwnership(newowner String) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 STORE("tmpowner",ADDRESS_RAW(newowner))
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// Until the new owner claims ownership, existing owner remains owner
|
||||
Function ClaimOwnership() Uint64
|
||||
10 IF LOAD("tmpowner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 STORE("owner",SIGNER()) // ownership claim successful
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// If signer is owner, withdraw any requested funds
|
||||
// If everthing is okay, they will be showing in signers wallet
|
||||
Function Withdraw( amount Uint64) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 SEND_DERO_TO_ADDRESS(SIGNER(),amount)
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// If signer is owner, provide him rights to update code anytime
|
||||
// make sure update is always available to SC
|
||||
Function UpdateCode( code String) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 UPDATE_SC_CODE(code)
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
|
25
tests/normal/multi_deposit_test/asset.bas
Normal file
25
tests/normal/multi_deposit_test/asset.bas
Normal file
@ -0,0 +1,25 @@
|
||||
/* Private Token Smart Contract Example in DVM-BASIC.
|
||||
DERO Smart Contracts Tokens privacy can be understood just like banks handle cash. Once cash is out from the bank, bank is not aware about it (who owns what value), until it is deposited back.
|
||||
Smart contract only maintains supply and other necessary items to keep it working.
|
||||
DERO Tokens can be tranfered to other wallets just like native DERO with Homomorphic Encryption and without involvement of issuing Smart Contracts.
|
||||
Token issuing Smart Contract cannot hold/freeze/control their tokens once they are issued and sent to any wallet.
|
||||
This token is Private. Use Function InitializePrivate() Uint64 to make any Smart Contract private.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
// Issue Asset after depositing DERO (Convert DERO to TOKENX)
|
||||
Function IssueAsset() Uint64
|
||||
10 SEND_ASSET_TO_ADDRESS(SIGNER(), DEROVALUE(),SCID()) // send asset without knowing original balance, this is done homomorphically
|
||||
20 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
// This function is used to initialize parameters during install time
|
||||
// InitializePrivate initializes a private SC
|
||||
Function InitializePrivate() Uint64
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
|
67
tests/normal/multi_deposit_test/asset_exchange.bas
Normal file
67
tests/normal/multi_deposit_test/asset_exchange.bas
Normal file
@ -0,0 +1,67 @@
|
||||
// Asset Interchange/Exchnage Smart Contract Example in DVM-BASIC.
|
||||
// This SC allows you to deposit an arbitrary token, into it
|
||||
// and later allows you to swap one token with another
|
||||
// if the SC has enough balance to cover outgoing transfer it will be done
|
||||
|
||||
|
||||
// deposits an arbitrary token
|
||||
// owner should deposits all arbitrary types
|
||||
|
||||
Function Deposit() Uint64
|
||||
20 RETURN 0
|
||||
End Function
|
||||
|
||||
// incoming represents incoming asset type basicallly an SCID
|
||||
// outgoing represents outgoing asset type basicallly an SCID
|
||||
Function Interchange(incoming String, outgoing String) Uint64
|
||||
10 SEND_ASSET_TO_ADDRESS(SIGNER(),ASSETVALUE(incoming)/2, outgoing) // 1 to 1 interchange of assets
|
||||
20 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
Function Initialize() Uint64
|
||||
10 STORE("owner", SIGNER()) // store in DB ["owner"] = address
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
// everything below this is supplementary and not required
|
||||
|
||||
// This function is used to change owner
|
||||
// owner is an string form of address
|
||||
Function TransferOwnership(newowner String) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 STORE("tmpowner",ADDRESS_RAW(newowner))
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// Until the new owner claims ownership, existing owner remains owner
|
||||
Function ClaimOwnership() Uint64
|
||||
10 IF LOAD("tmpowner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 STORE("owner",SIGNER()) // ownership claim successful
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// if signer is owner, withdraw any requested funds
|
||||
// if everthing is okay, they will be showing in signers wallet
|
||||
Function Withdraw(amount Uint64, asset String) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 SEND_ASSET_TO_ADDRESS(SIGNER(),amount,asset)
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// if signer is owner, provide him rights to update code anytime
|
||||
// make sure update is always available to SC
|
||||
Function UpdateCode( code String) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 UPDATE_SC_CODE(code)
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
|
110
tests/normal/multi_deposit_test/run_test.sh
Executable file
110
tests/normal/multi_deposit_test/run_test.sh
Executable file
@ -0,0 +1,110 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#set -x # to enable debug and verbose printing of each and every command
|
||||
|
||||
# the SC will trigger panic and but cannot return the funds to sender since ringsize > 2, instead deposits to SC
|
||||
|
||||
CURDIR=`/bin/pwd`
|
||||
BASEDIR=$(dirname $0)
|
||||
ABSPATH=$(readlink -f $0)
|
||||
ABSDIR=$(dirname $ABSPATH)
|
||||
|
||||
command -v curl >/dev/null 2>&1 || { echo "I require curl but it's not installed. Aborting." >&2; exit 1; }
|
||||
command -v jq >/dev/null 2>&1 || { echo "I require jq but it's not installed. Aborting." >&2; exit 1; }
|
||||
|
||||
baseasset="0000000000000000000000000000000000000000000000000000000000000000"
|
||||
|
||||
daemon_rpc_port="20000" # daemon rpc is listening on this port
|
||||
|
||||
# we have number of wallets listening at ports from 30000
|
||||
# we will be using 3 wallets, named owner, player1,player2
|
||||
owner_rpc_port="30000"
|
||||
player1_rpc_port="30001"
|
||||
player2_rpc_port="30002"
|
||||
|
||||
owner_address=$(curl --silent http://127.0.0.1:$owner_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
player1_address=$(curl --silent http://127.0.0.1:$player1_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
player2_address=$(curl --silent http://127.0.0.1:$player2_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
|
||||
|
||||
function balance(){
|
||||
curl --silent http://127.0.0.1:$1/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getbalance"}' -H 'Content-Type: application/json'| jq -r ".result.balance"
|
||||
}
|
||||
|
||||
function scassetbalance(){
|
||||
curl --silent http://127.0.0.1:$daemon_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getsc","params":{ "scid":"'"$1"'" , "code":false, "variables":true}}' -H 'Content-Type: application/json'| jq -r '.result.balances."'$2'"'
|
||||
}
|
||||
|
||||
function tokenbalance(){
|
||||
curl --silent http://127.0.0.1:$1/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getbalance" , "params":{ "scid":"'"$2"'" }}' -H 'Content-Type: application/json'| jq -r ".result.balance"
|
||||
}
|
||||
|
||||
owner_rpc_port="30000"
|
||||
user1_rpc_port="30001"
|
||||
user2_rpc_port="30002"
|
||||
|
||||
owner_address=$(curl --silent http://127.0.0.1:$owner_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
user1_address=$(curl --silent http://127.0.0.1:$user1_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
user2_address=$(curl --silent http://127.0.0.1:$user2_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
|
||||
|
||||
# use owner wallet to load/install an lotter sc to chain
|
||||
exchangescid=$(curl --silent --request POST --data-binary @asset_exchange.bas http://127.0.0.1:$owner_rpc_port/install_sc| jq -r ".txid")
|
||||
echo "exchange SCID" $exchangescid
|
||||
sleep 2
|
||||
|
||||
asset1scid=$(curl --silent --request POST --data-binary @asset.bas http://127.0.0.1:$owner_rpc_port/install_sc| jq -r ".txid")
|
||||
echo "asset1 SCID" $asset1scid
|
||||
sleep 2
|
||||
|
||||
|
||||
asset2scid=$(curl --silent --request POST --data-binary @asset.bas http://127.0.0.1:$owner_rpc_port/install_sc| jq -r ".txid")
|
||||
echo "asset2 SCID" $asset2scid
|
||||
sleep 2
|
||||
|
||||
|
||||
echo -n "owner exchanging dero 1000 for asset1 "
|
||||
curl --silent http://127.0.0.1:$owner_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"scinvoke","params":{"sc_dero_deposit":1000,"scid":"'"$asset1scid"'","ringsize":2, "sc_rpc":[{"name":"entrypoint","datatype":"S","value":"IssueAsset"}] }}' -H 'Content-Type: application/json' | jq -r ".result.txid"
|
||||
sleep 2
|
||||
echo -n "owner exchanging dero 1000 for asset2 "
|
||||
curl --silent http://127.0.0.1:$owner_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"scinvoke","params":{"sc_dero_deposit":1000,"scid":"'"$asset2scid"'","ringsize":2, "sc_rpc":[{"name":"entrypoint","datatype":"S","value":"IssueAsset"}] }}' -H 'Content-Type: application/json' | jq -r ".result.txid"
|
||||
sleep 2
|
||||
|
||||
|
||||
echo -n "owner depositing triple assets ( dero, asset1, asset2 ) to exchangescid "
|
||||
curl --silent http://127.0.0.1:$owner_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"transfer","params":{"scid":"'"$exchangescid"'","ringsize":2, "sc_rpc":[{"name":"entrypoint","datatype":"S","value":"Deposit"}], "transfers": [{"burn":1234,"destination":"'"$user2_address"'"}, {"scid":"'"$asset1scid"'", "burn":123}, {"scid":"'"$asset2scid"'", "burn":555}] }}' -H 'Content-Type: application/json' | jq -r ".result.txid"
|
||||
sleep 2
|
||||
|
||||
|
||||
echo "SC DERO balance" $(scassetbalance $exchangescid $baseasset )
|
||||
echo "SC Asset1 balance" $(scassetbalance $exchangescid $asset1scid )
|
||||
echo "SC Asset2 balance" $(scassetbalance $exchangescid $asset2scid )
|
||||
|
||||
|
||||
if [[ $(scassetbalance $exchangescid $baseasset) -ne 1234 || $(scassetbalance $exchangescid $asset1scid) -ne 123 || $(scassetbalance $exchangescid $asset2scid) -ne 555 ]] ; then
|
||||
echo "condition failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
echo -n "user1 exchanging dero 2000 for asset1 "
|
||||
curl --silent http://127.0.0.1:$user1_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"scinvoke","params":{"sc_dero_deposit":2000,"scid":"'"$asset1scid"'","ringsize":2, "sc_rpc":[{"name":"entrypoint","datatype":"S","value":"IssueAsset"}] }}' -H 'Content-Type: application/json' | jq -r ".result.txid"
|
||||
sleep 2
|
||||
echo "wallet1 received asset1 tokens in return" $(tokenbalance $user1_rpc_port $asset1scid)
|
||||
|
||||
|
||||
echo -n "user1 depositing 122 asset1 to obtain 61 asset2"
|
||||
curl --silent http://127.0.0.1:$user1_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"transfer","params":{"scid":"'"$exchangescid"'","ringsize":2, "sc_rpc":[{"name":"entrypoint","datatype":"S","value":"Interchange"},{"name":"incoming","datatype":"H","value":"'"$asset1scid"'"},{"name":"outgoing","datatype":"H","value":"'"$asset2scid"'"}], "transfers": [{"scid":"'"$asset1scid"'", "burn":122}] }}' -H 'Content-Type: application/json' | jq -r ".result.txid"
|
||||
#curl --silent http://127.0.0.1:$user1_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"scinvoke","params":{"sc_dero_deposit":10000,"scid":"'"$exchangescid"'","ringsize":2, "sc_rpc":[] }}' -H 'Content-Type: application/json' | jq -r ".result.txid"
|
||||
|
||||
|
||||
sleep 2
|
||||
echo "wallet1 asset1 tokens " $(tokenbalance $user1_rpc_port $asset1scid)
|
||||
echo "wallet1 asset2 tokens after exchange " $(tokenbalance $user1_rpc_port $asset2scid)
|
||||
|
||||
if [[ $(tokenbalance $user1_rpc_port $asset1scid) -ne 1878 || $(tokenbalance $user1_rpc_port $asset2scid) -ne 61 ]] ; then
|
||||
echo "condition failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
63
tests/normal/panic_no_return_funds_test/run_test.sh
Executable file
63
tests/normal/panic_no_return_funds_test/run_test.sh
Executable file
@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#set -x # to enable debug and verbose printing of each and every command
|
||||
|
||||
# the SC will trigger panic and but cannot return the funds to sender since ringsize > 2, instead deposits to SC
|
||||
|
||||
CURDIR=`/bin/pwd`
|
||||
BASEDIR=$(dirname $0)
|
||||
ABSPATH=$(readlink -f $0)
|
||||
ABSDIR=$(dirname $ABSPATH)
|
||||
|
||||
command -v curl >/dev/null 2>&1 || { echo "I require curl but it's not installed. Aborting." >&2; exit 1; }
|
||||
command -v jq >/dev/null 2>&1 || { echo "I require jq but it's not installed. Aborting." >&2; exit 1; }
|
||||
|
||||
baseasset="0000000000000000000000000000000000000000000000000000000000000000"
|
||||
|
||||
daemon_rpc_port="20000" # daemon rpc is listening on this port
|
||||
|
||||
# we have number of wallets listening at ports from 30000
|
||||
# we will be using 3 wallets, named owner, player1,player2
|
||||
owner_rpc_port="30000"
|
||||
player1_rpc_port="30001"
|
||||
player2_rpc_port="30002"
|
||||
|
||||
owner_address=$(curl --silent http://127.0.0.1:$owner_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
player1_address=$(curl --silent http://127.0.0.1:$player1_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
player2_address=$(curl --silent http://127.0.0.1:$player2_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
|
||||
|
||||
function balance(){
|
||||
curl --silent http://127.0.0.1:$1/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getbalance"}' -H 'Content-Type: application/json'| jq -r ".result.balance"
|
||||
}
|
||||
|
||||
function scassetbalance(){
|
||||
curl --silent http://127.0.0.1:$daemon_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getsc","params":{ "scid":"'"$1"'" , "code":false, "variables":true}}' -H 'Content-Type: application/json'| jq -r '.result.balances."'$2'"'
|
||||
}
|
||||
|
||||
echo "SC owner address" $owner_address
|
||||
echo "player1 address" $player1_address
|
||||
echo "player2 address" $player2_address
|
||||
|
||||
|
||||
# use owner wallet to load/install an lotter sc to chain
|
||||
scid=$(curl --silent --request POST --data-binary @test.bas http://127.0.0.1:$owner_rpc_port/install_sc| jq -r ".txid")
|
||||
echo "SCID" $scid
|
||||
sleep 2
|
||||
|
||||
|
||||
echo -n "Player 1 play txid "
|
||||
curl --silent http://127.0.0.1:$player1_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"scinvoke","params":{"sc_dero_deposit":500000,"scid":"'"$scid"'","ringsize":4, "sc_rpc":[{"name":"entrypoint","datatype":"S","value":"Lottery"}] }}' -H 'Content-Type: application/json' | jq -r ".result.txid"
|
||||
|
||||
sleep 4
|
||||
|
||||
echo "SC DERO balance" $(scassetbalance $scid $baseasset )
|
||||
echo "SC owner balance" $(balance $owner_rpc_port)
|
||||
echo "SC player1 balance" $(balance $player1_rpc_port)
|
||||
|
||||
player1_balance=$(balance $player1_rpc_port)
|
||||
if [[ $player1_balance -gt 700000 ]] ; then
|
||||
exit 1
|
||||
else
|
||||
exit 0
|
||||
fi
|
94
tests/normal/panic_no_return_funds_test/test.bas
Normal file
94
tests/normal/panic_no_return_funds_test/test.bas
Normal file
@ -0,0 +1,94 @@
|
||||
/* Lottery Smart Contract Example in DVM-BASIC.
|
||||
This lottery smart contract will give lottery wins on every second try in following default contract.
|
||||
Make depost transaction to this SCID to play lottery.
|
||||
Check https://github.com/deroproject/derohe/blob/main/guide/examples/lottery_sc_guide.md
|
||||
*/
|
||||
|
||||
|
||||
|
||||
Function Lottery() Uint64
|
||||
5 PANIC()
|
||||
10 dim deposit_count,winner as Uint64
|
||||
20 LET deposit_count = LOAD("deposit_count")+1
|
||||
25 IF DEROVALUE() == 0 THEN GOTO 110 // if deposit amount is 0, simply return
|
||||
30 STORE("depositor_address" + (deposit_count-1), SIGNER()) // store address for later on payment
|
||||
40 STORE("deposit_total", LOAD("deposit_total") + DEROVALUE() )
|
||||
50 STORE("deposit_count",deposit_count)
|
||||
60 IF LOAD("lotteryeveryXdeposit") > deposit_count THEN GOTO 110 // we will wait till X players join in
|
||||
// we are here means all players have joined in, roll the DICE,
|
||||
70 LET winner = RANDOM() % deposit_count // we have a winner
|
||||
80 SEND_DERO_TO_ADDRESS(LOAD("depositor_address" + winner) , LOAD("lotterygiveback")*LOAD("deposit_total")/10000)
|
||||
// Re-Initialize for another round
|
||||
90 STORE("deposit_count", 0) // initial players
|
||||
100 STORE("deposit_total", 0) // total deposit of all players
|
||||
110 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
// This function is used to initialize parameters during install time
|
||||
Function Initialize() Uint64
|
||||
5 version("1.2.3")
|
||||
10 STORE("owner", SIGNER()) // store in DB ["owner"] = address
|
||||
20 STORE("lotteryeveryXdeposit", 2) // lottery will reward every X deposits
|
||||
// How much will lottery giveback in 1/10000 parts, granularity .01 %
|
||||
30 STORE("lotterygiveback", 9900) // lottery will give reward 99% of deposits, 1 % is accumulated for owner to withdraw
|
||||
33 STORE("deposit_count", 0) // initial players
|
||||
34 STORE("deposit_total", 0) // total deposit of all players
|
||||
// 35 printf "Initialize executed"
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
// Function to tune lottery parameters
|
||||
Function TuneLotteryParameters(input Uint64, lotteryeveryXdeposit Uint64, lotterygiveback Uint64) Uint64
|
||||
10 dim key,stored_owner as String
|
||||
20 dim value_uint64 as Uint64
|
||||
30 IF LOAD("owner") == SIGNER() THEN GOTO 100 // check whether owner is real owner
|
||||
40 RETURN 1
|
||||
|
||||
100 STORE("lotteryeveryXdeposit", lotteryeveryXdeposit) // lottery will reward every X deposits
|
||||
130 STORE("lotterygiveback", value_uint64) // how much will lottery giveback in 1/10000 parts, granularity .01 %
|
||||
140 RETURN 0 // return success
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
// This function is used to change owner
|
||||
// owner is an string form of address
|
||||
Function TransferOwnership(newowner String) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 STORE("tmpowner",ADDRESS_RAW(newowner))
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// Until the new owner claims ownership, existing owner remains owner
|
||||
Function ClaimOwnership() Uint64
|
||||
10 IF LOAD("tmpowner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 STORE("owner",SIGNER()) // ownership claim successful
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// If signer is owner, withdraw any requested funds
|
||||
// If everthing is okay, they will be showing in signers wallet
|
||||
Function Withdraw( amount Uint64) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 SEND_DERO_TO_ADDRESS(SIGNER(),amount)
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// If signer is owner, provide him rights to update code anytime
|
||||
// make sure update is always available to SC
|
||||
Function UpdateCode( code String) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 UPDATE_SC_CODE(code)
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
|
67
tests/normal/panic_return_funds_test/run_test.sh
Executable file
67
tests/normal/panic_return_funds_test/run_test.sh
Executable file
@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#set -x # to enable debug and verbose printing of each and every command
|
||||
|
||||
# the SC will trigger panic and will return the funds
|
||||
CURDIR=`/bin/pwd`
|
||||
BASEDIR=$(dirname $0)
|
||||
ABSPATH=$(readlink -f $0)
|
||||
ABSDIR=$(dirname $ABSPATH)
|
||||
|
||||
command -v curl >/dev/null 2>&1 || { echo "I require curl but it's not installed. Aborting." >&2; exit 1; }
|
||||
command -v jq >/dev/null 2>&1 || { echo "I require jq but it's not installed. Aborting." >&2; exit 1; }
|
||||
|
||||
|
||||
daemon_rpc_port="20000" # daemon rpc is listening on this port
|
||||
|
||||
# we have number of wallets listening at ports from 30000
|
||||
# we will be using 3 wallets, named owner, player1,player2
|
||||
owner_rpc_port="30000"
|
||||
player1_rpc_port="30001"
|
||||
player2_rpc_port="30002"
|
||||
|
||||
owner_address=$(curl --silent http://127.0.0.1:$owner_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
player1_address=$(curl --silent http://127.0.0.1:$player1_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
player2_address=$(curl --silent http://127.0.0.1:$player2_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
|
||||
|
||||
function balance(){
|
||||
curl --silent http://127.0.0.1:$1/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getbalance"}' -H 'Content-Type: application/json'| jq -r ".result.balance"
|
||||
}
|
||||
|
||||
function scbalance(){
|
||||
curl --silent http://127.0.0.1:$daemon_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getsc","params":{ "scid":"'"$1"'" , "code":false, "keysstring":["deposit_count"]}}' -H 'Content-Type: application/json' | jq -r ".result.balance"
|
||||
}
|
||||
|
||||
echo "SC owner address" $owner_address
|
||||
echo "player1 address" $player1_address
|
||||
echo "player2 address" $player2_address
|
||||
|
||||
|
||||
# use owner wallet to load/install an lotter sc to chain
|
||||
scid=$(curl --silent --request POST --data-binary @test.bas http://127.0.0.1:$owner_rpc_port/install_sc| jq -r ".txid")
|
||||
echo "SCID" $scid
|
||||
sleep 1
|
||||
|
||||
|
||||
#curl --silent http://127.0.0.1:$daemon_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getsc","params":{ "scid":"'"$scid"'" , "code":false, "keysstring":["deposit_count"]}}' -H 'Content-Type: application/json'
|
||||
|
||||
echo -n "Player 1 play txid "
|
||||
curl --silent http://127.0.0.1:$player1_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"scinvoke","params":{"sc_dero_deposit":300000,"scid":"'"$scid"'","ringsize":2, "sc_rpc":[{"name":"entrypoint","datatype":"S","value":"Lottery"}] }}' -H 'Content-Type: application/json' | jq -r ".result.txid"
|
||||
|
||||
|
||||
curl --silent http://127.0.0.1:$daemon_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getsc","params":{ "scid":"'"$scid"'" , "code":false, "keysstring":["deposit_count"]}}' -H 'Content-Type: application/json' | jq -r ".result.balance"
|
||||
|
||||
sleep 2
|
||||
|
||||
echo "SC balance" $(scbalance $scid)
|
||||
echo "SC owner balance" $(balance $owner_rpc_port)
|
||||
echo "SC player1 balance" $(balance $player1_rpc_port)
|
||||
|
||||
player1_balance=$(balance $player1_rpc_port)
|
||||
echo "player1 balance $player1_balance"
|
||||
if [[ $player1_balance -gt 700000 ]] ; then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
94
tests/normal/panic_return_funds_test/test.bas
Normal file
94
tests/normal/panic_return_funds_test/test.bas
Normal file
@ -0,0 +1,94 @@
|
||||
/* Lottery Smart Contract Example in DVM-BASIC.
|
||||
This lottery smart contract will give lottery wins on every second try in following default contract.
|
||||
Make depost transaction to this SCID to play lottery.
|
||||
Check https://github.com/deroproject/derohe/blob/main/guide/examples/lottery_sc_guide.md
|
||||
*/
|
||||
|
||||
|
||||
|
||||
Function Lottery() Uint64
|
||||
5 PANIC()
|
||||
10 dim deposit_count,winner as Uint64
|
||||
20 LET deposit_count = LOAD("deposit_count")+1
|
||||
25 IF DEROVALUE() == 0 THEN GOTO 110 // if deposit amount is 0, simply return
|
||||
30 STORE("depositor_address" + (deposit_count-1), SIGNER()) // store address for later on payment
|
||||
40 STORE("deposit_total", LOAD("deposit_total") + DEROVALUE() )
|
||||
50 STORE("deposit_count",deposit_count)
|
||||
60 IF LOAD("lotteryeveryXdeposit") > deposit_count THEN GOTO 110 // we will wait till X players join in
|
||||
// we are here means all players have joined in, roll the DICE,
|
||||
70 LET winner = RANDOM() % deposit_count // we have a winner
|
||||
80 SEND_DERO_TO_ADDRESS(LOAD("depositor_address" + winner) , LOAD("lotterygiveback")*LOAD("deposit_total")/10000)
|
||||
// Re-Initialize for another round
|
||||
90 STORE("deposit_count", 0) // initial players
|
||||
100 STORE("deposit_total", 0) // total deposit of all players
|
||||
110 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
// This function is used to initialize parameters during install time
|
||||
Function Initialize() Uint64
|
||||
5 version("1.2.3")
|
||||
10 STORE("owner", SIGNER()) // store in DB ["owner"] = address
|
||||
20 STORE("lotteryeveryXdeposit", 2) // lottery will reward every X deposits
|
||||
// How much will lottery giveback in 1/10000 parts, granularity .01 %
|
||||
30 STORE("lotterygiveback", 9900) // lottery will give reward 99% of deposits, 1 % is accumulated for owner to withdraw
|
||||
33 STORE("deposit_count", 0) // initial players
|
||||
34 STORE("deposit_total", 0) // total deposit of all players
|
||||
// 35 printf "Initialize executed"
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
// Function to tune lottery parameters
|
||||
Function TuneLotteryParameters(input Uint64, lotteryeveryXdeposit Uint64, lotterygiveback Uint64) Uint64
|
||||
10 dim key,stored_owner as String
|
||||
20 dim value_uint64 as Uint64
|
||||
30 IF LOAD("owner") == SIGNER() THEN GOTO 100 // check whether owner is real owner
|
||||
40 RETURN 1
|
||||
|
||||
100 STORE("lotteryeveryXdeposit", lotteryeveryXdeposit) // lottery will reward every X deposits
|
||||
130 STORE("lotterygiveback", value_uint64) // how much will lottery giveback in 1/10000 parts, granularity .01 %
|
||||
140 RETURN 0 // return success
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
// This function is used to change owner
|
||||
// owner is an string form of address
|
||||
Function TransferOwnership(newowner String) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 STORE("tmpowner",ADDRESS_RAW(newowner))
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// Until the new owner claims ownership, existing owner remains owner
|
||||
Function ClaimOwnership() Uint64
|
||||
10 IF LOAD("tmpowner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 STORE("owner",SIGNER()) // ownership claim successful
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// If signer is owner, withdraw any requested funds
|
||||
// If everthing is okay, they will be showing in signers wallet
|
||||
Function Withdraw( amount Uint64) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 SEND_DERO_TO_ADDRESS(SIGNER(),amount)
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// If signer is owner, provide him rights to update code anytime
|
||||
// make sure update is always available to SC
|
||||
Function UpdateCode( code String) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 UPDATE_SC_CODE(code)
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
|
68
tests/normal/rammap_test/run_test.sh
Executable file
68
tests/normal/rammap_test/run_test.sh
Executable file
@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#set -x # to enable debug and verbose printing of each and every command
|
||||
|
||||
CURDIR=`/bin/pwd`
|
||||
BASEDIR=$(dirname $0)
|
||||
ABSPATH=$(readlink -f $0)
|
||||
ABSDIR=$(dirname $ABSPATH)
|
||||
|
||||
|
||||
command -v curl >/dev/null 2>&1 || { echo "I require curl but it's not installed. Aborting." >&2; exit 1; }
|
||||
command -v jq >/dev/null 2>&1 || { echo "I require jq but it's not installed. Aborting." >&2; exit 1; }
|
||||
|
||||
|
||||
daemon_rpc_port="20000" # daemon rpc is listening on this port
|
||||
|
||||
# we have number of wallets listening at ports from 30000
|
||||
# we will be using 3 wallets, named owner, player1,player2
|
||||
owner_rpc_port="30000"
|
||||
player1_rpc_port="30001"
|
||||
player2_rpc_port="30002"
|
||||
|
||||
owner_address=$(curl --silent http://127.0.0.1:$owner_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
player1_address=$(curl --silent http://127.0.0.1:$player1_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
player2_address=$(curl --silent http://127.0.0.1:$player2_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
|
||||
|
||||
function balance(){
|
||||
curl --silent http://127.0.0.1:$1/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getbalance"}' -H 'Content-Type: application/json'| jq -r ".result.balance"
|
||||
}
|
||||
|
||||
function scbalance(){
|
||||
curl --silent http://127.0.0.1:$daemon_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getsc","params":{ "scid":"'"$1"'" , "code":false, "keysstring":["deposit_count"]}}' -H 'Content-Type: application/json' | jq -r ".result.balance"
|
||||
}
|
||||
|
||||
echo "SC owner address" $owner_address
|
||||
echo "player1 address" $player1_address
|
||||
echo "player2 address" $player2_address
|
||||
|
||||
|
||||
# use owner wallet to load/install an lotter sc to chain
|
||||
scid=$(curl --silent --request POST --data-binary @test.bas http://127.0.0.1:$owner_rpc_port/install_sc| jq -r ".txid")
|
||||
echo "SCID" $scid
|
||||
sleep 1
|
||||
|
||||
|
||||
#curl --silent http://127.0.0.1:$daemon_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getsc","params":{ "scid":"'"$scid"'" , "code":false, "keysstring":["deposit_count"]}}' -H 'Content-Type: application/json'
|
||||
|
||||
echo -n "Player 1 play txid "
|
||||
curl --silent http://127.0.0.1:$player1_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"scinvoke","params":{"sc_dero_deposit":3000,"scid":"'"$scid"'","ringsize":2, "sc_rpc":[{"name":"entrypoint","datatype":"S","value":"Lottery"}] }}' -H 'Content-Type: application/json' | jq -r ".result.txid"
|
||||
echo -n "Player 2 play txid "
|
||||
curl --silent http://127.0.0.1:$player2_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"scinvoke","params":{"sc_dero_deposit":3000,"scid":"'"$scid"'","ringsize":2, "sc_rpc":[{"name":"entrypoint","datatype":"S","value":"Lottery"}] }}' -H 'Content-Type: application/json' | jq -r ".result.txid"
|
||||
sleep 2
|
||||
|
||||
curl --silent http://127.0.0.1:$daemon_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getsc","params":{ "scid":"'"$scid"'" , "code":false, "keysstring":["deposit_count"]}}' -H 'Content-Type: application/json' | jq -r ".result.balance"
|
||||
|
||||
|
||||
echo "SC balance" $(scbalance $scid)
|
||||
echo "SC owner balance" $(balance $owner_rpc_port)
|
||||
echo "SC player1 balance" $(balance $player1_rpc_port)
|
||||
echo "SC player2 balance" $(balance $player2_rpc_port)
|
||||
|
||||
if [[ $(balance $player1_rpc_port) -gt 800000 || $(balance $player2_rpc_port) -gt 800000 ]]
|
||||
then
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
101
tests/normal/rammap_test/test.bas
Normal file
101
tests/normal/rammap_test/test.bas
Normal file
@ -0,0 +1,101 @@
|
||||
/* Lottery Smart Contract Example in DVM-BASIC.
|
||||
This lottery smart contract will give lottery wins on every second try in following default contract.
|
||||
Make depost transaction to this SCID to play lottery.
|
||||
Check https://github.com/deroproject/derohe/blob/main/guide/examples/lottery_sc_guide.md
|
||||
*/
|
||||
|
||||
|
||||
|
||||
Function Lottery() Uint64
|
||||
10 dim deposit_count,winner as Uint64
|
||||
20 LET deposit_count = LOAD("deposit_count")+1
|
||||
25 IF DEROVALUE() == 0 THEN GOTO 110 // if deposit amount is 0, simply return
|
||||
30 STORE("depositor_address" + (deposit_count-1), SIGNER()) // store address for later on payment
|
||||
40 STORE("deposit_total", LOAD("deposit_total") + DEROVALUE() )
|
||||
50 STORE("deposit_count",deposit_count)
|
||||
60 IF LOAD("lotteryeveryXdeposit") > deposit_count THEN GOTO 110 // we will wait till X players join in
|
||||
// we are here means all players have joined in, roll the DICE,
|
||||
70 LET winner = RANDOM() % deposit_count // we have a winner
|
||||
80 SEND_DERO_TO_ADDRESS(LOAD("depositor_address" + winner) , LOAD("lotterygiveback")*LOAD("deposit_total")/10000)
|
||||
// Re-Initialize for another round
|
||||
90 STORE("deposit_count", 0) // initial players
|
||||
100 STORE("deposit_total", 0) // total deposit of all players
|
||||
110 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
function q()
|
||||
10 MAPSTORE(2, 2) // this will store to ram
|
||||
20 return
|
||||
End function
|
||||
// This function is used to initialize parameters during install time
|
||||
Function Initialize() Uint64
|
||||
5 MAPSTORE("owner", SIGNER())
|
||||
10 STORE("owner", MAPGET("owner")) // store in DB ["owner"] = address
|
||||
15 q()
|
||||
20 STORE("lotteryeveryXdeposit", MAPGET(2)) //,, recover value stored in function q, lottery will reward every X deposits
|
||||
// How much will lottery giveback in 1/10000 parts, granularity .01 %
|
||||
30 STORE("lotterygiveback", 9900) // lottery will give reward 99% of deposits, 1 % is accumulated for owner to withdraw
|
||||
33 STORE("deposit_count", 0) // initial players
|
||||
34 STORE("deposit_total", 0) // total deposit of all players
|
||||
// 35 printf "Initialize executed"
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Function to tune lottery parameters
|
||||
Function TuneLotteryParameters(input Uint64, lotteryeveryXdeposit Uint64, lotterygiveback Uint64) Uint64
|
||||
10 dim key,stored_owner as String
|
||||
20 dim value_uint64 as Uint64
|
||||
30 IF LOAD("owner") == SIGNER() THEN GOTO 100 // check whether owner is real owner
|
||||
40 RETURN 1
|
||||
|
||||
100 STORE("lotteryeveryXdeposit", lotteryeveryXdeposit) // lottery will reward every X deposits
|
||||
130 STORE("lotterygiveback", value_uint64) // how much will lottery giveback in 1/10000 parts, granularity .01 %
|
||||
140 RETURN 0 // return success
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
// This function is used to change owner
|
||||
// owner is an string form of address
|
||||
Function TransferOwnership(newowner String) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 STORE("tmpowner",ADDRESS_RAW(newowner))
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// Until the new owner claims ownership, existing owner remains owner
|
||||
Function ClaimOwnership() Uint64
|
||||
10 IF LOAD("tmpowner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 STORE("owner",SIGNER()) // ownership claim successful
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// If signer is owner, withdraw any requested funds
|
||||
// If everthing is okay, they will be showing in signers wallet
|
||||
Function Withdraw( amount Uint64) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 SEND_DERO_TO_ADDRESS(SIGNER(),amount)
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// If signer is owner, provide him rights to update code anytime
|
||||
// make sure update is always available to SC
|
||||
Function UpdateCode( code String) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 UPDATE_SC_CODE(code)
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
|
70
tests/specific/lottery_within_block_1panic_1success_test/run_test.sh
Executable file
70
tests/specific/lottery_within_block_1panic_1success_test/run_test.sh
Executable file
@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#set -x # to enable debug and verbose printing of each and every command
|
||||
|
||||
# this will test case if lottery can run within a block
|
||||
|
||||
CURDIR=`/bin/pwd`
|
||||
BASEDIR=$(dirname $0)
|
||||
ABSPATH=$(readlink -f $0)
|
||||
ABSDIR=$(dirname $ABSPATH)
|
||||
|
||||
command -v curl >/dev/null 2>&1 || { echo "I require curl but it's not installed. Aborting." >&2; exit 1; }
|
||||
command -v jq >/dev/null 2>&1 || { echo "I require jq but it's not installed. Aborting." >&2; exit 1; }
|
||||
|
||||
baseasset="0000000000000000000000000000000000000000000000000000000000000000"
|
||||
|
||||
daemon_rpc_port="20000" # daemon rpc is listening on this port
|
||||
|
||||
# we have number of wallets listening at ports from 30000
|
||||
# we will be using 3 wallets, named owner, player1,player2
|
||||
owner_rpc_port="30000"
|
||||
player1_rpc_port="30001"
|
||||
player2_rpc_port="30002"
|
||||
|
||||
owner_address=$(curl --silent http://127.0.0.1:$owner_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
player1_address=$(curl --silent http://127.0.0.1:$player1_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
player2_address=$(curl --silent http://127.0.0.1:$player2_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
|
||||
|
||||
function balance(){
|
||||
curl --silent http://127.0.0.1:$1/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getbalance"}' -H 'Content-Type: application/json'| jq -r ".result.balance"
|
||||
}
|
||||
|
||||
function scassetbalance(){
|
||||
curl --silent http://127.0.0.1:$daemon_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getsc","params":{ "scid":"'"$1"'" , "code":false, "variables":true}}' -H 'Content-Type: application/json'| jq -r '.result.balances."'$2'"'
|
||||
}
|
||||
|
||||
function mineblock(){
|
||||
touch /dev/shm/mineblocknow
|
||||
}
|
||||
|
||||
echo "SC owner address" $owner_address
|
||||
echo "player1 address" $player1_address
|
||||
echo "player2 address" $player2_address
|
||||
|
||||
|
||||
# use owner wallet to load/install an lotter sc to chain
|
||||
scid=$(curl --silent --request POST --data-binary @test.bas http://127.0.0.1:$owner_rpc_port/install_sc| jq -r ".txid")
|
||||
echo "SCID" $scid
|
||||
mineblock
|
||||
sleep 2
|
||||
|
||||
|
||||
echo -n "2 players playing txid "
|
||||
curl --silent http://127.0.0.1:$player1_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"scinvoke","params":{"sc_dero_deposit":500000,"scid":"'"$scid"'","ringsize":2, "sc_rpc":[{"name":"entrypoint","datatype":"S","value":"Lottery"}] }}' -H 'Content-Type: application/json' | jq -r ".result.txid"
|
||||
curl --silent http://127.0.0.1:$player2_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"scinvoke","params":{"sc_dero_deposit":400000,"scid":"'"$scid"'","ringsize":2, "sc_rpc":[{"name":"entrypoint","datatype":"S","value":"Lottery"}] }}' -H 'Content-Type: application/json' | jq -r ".result.txid"
|
||||
mineblock
|
||||
sleep 4
|
||||
|
||||
echo "SC DERO balance" $(scassetbalance $scid $baseasset )
|
||||
echo "SC owner balance" $(balance $owner_rpc_port)
|
||||
echo "SC player1 balance" $(balance $player1_rpc_port)
|
||||
echo "SC player2 balance" $(balance $player2_rpc_port)
|
||||
|
||||
if [[ $(balance $player1_rpc_port) -lt 300000 && $(balance $player2_rpc_port) -gt 790000 ]] ; then
|
||||
exit 0
|
||||
else
|
||||
echo "test failed"
|
||||
exit 1
|
||||
fi
|
@ -0,0 +1,96 @@
|
||||
/* Lottery Smart Contract Example in DVM-BASIC.
|
||||
This lottery smart contract will give lottery wins on every second try in following default contract.
|
||||
Make depost transaction to this SCID to play lottery.
|
||||
Check https://github.com/deroproject/derohe/blob/main/guide/examples/lottery_sc_guide.md
|
||||
*/
|
||||
|
||||
|
||||
|
||||
Function Lottery() Uint64
|
||||
10 dim deposit_count,winner as Uint64
|
||||
20 LET deposit_count = LOAD("deposit_count")+1
|
||||
25 IF DEROVALUE() == 0 THEN GOTO 110 // if deposit amount is 0, simply return
|
||||
27 IF DEROVALUE() == 400000 THEN GOTO 120 // if deposit amount is 400000, panic
|
||||
30 STORE("depositor_address" + (deposit_count-1), SIGNER()) // store address for later on payment
|
||||
40 STORE("deposit_total", LOAD("deposit_total") + DEROVALUE() )
|
||||
50 STORE("deposit_count",deposit_count)
|
||||
60 IF LOAD("lotteryeveryXdeposit") > deposit_count THEN GOTO 110 // we will wait till X players join in
|
||||
// we are here means all players have joined in, roll the DICE,
|
||||
70 LET winner = RANDOM() % deposit_count // we have a winner
|
||||
80 SEND_DERO_TO_ADDRESS(LOAD("depositor_address" + winner) , LOAD("lotterygiveback")*LOAD("deposit_total")/10000)
|
||||
// Re-Initialize for another round
|
||||
90 STORE("deposit_count", 0) // initial players
|
||||
100 STORE("deposit_total", 0) // total deposit of all players
|
||||
110 RETURN 0
|
||||
120 PANIC()
|
||||
130 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
// This function is used to initialize parameters during install time
|
||||
Function Initialize() Uint64
|
||||
5 version("1.2.3")
|
||||
10 STORE("owner", SIGNER()) // store in DB ["owner"] = address
|
||||
20 STORE("lotteryeveryXdeposit", 2) // lottery will reward every X deposits
|
||||
// How much will lottery giveback in 1/10000 parts, granularity .01 %
|
||||
30 STORE("lotterygiveback", 9900) // lottery will give reward 99% of deposits, 1 % is accumulated for owner to withdraw
|
||||
33 STORE("deposit_count", 0) // initial players
|
||||
34 STORE("deposit_total", 0) // total deposit of all players
|
||||
// 35 printf "Initialize executed"
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
// Function to tune lottery parameters
|
||||
Function TuneLotteryParameters(input Uint64, lotteryeveryXdeposit Uint64, lotterygiveback Uint64) Uint64
|
||||
10 dim key,stored_owner as String
|
||||
20 dim value_uint64 as Uint64
|
||||
30 IF LOAD("owner") == SIGNER() THEN GOTO 100 // check whether owner is real owner
|
||||
40 RETURN 1
|
||||
|
||||
100 STORE("lotteryeveryXdeposit", lotteryeveryXdeposit) // lottery will reward every X deposits
|
||||
130 STORE("lotterygiveback", value_uint64) // how much will lottery giveback in 1/10000 parts, granularity .01 %
|
||||
140 RETURN 0 // return success
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
// This function is used to change owner
|
||||
// owner is an string form of address
|
||||
Function TransferOwnership(newowner String) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 STORE("tmpowner",ADDRESS_RAW(newowner))
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// Until the new owner claims ownership, existing owner remains owner
|
||||
Function ClaimOwnership() Uint64
|
||||
10 IF LOAD("tmpowner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 STORE("owner",SIGNER()) // ownership claim successful
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// If signer is owner, withdraw any requested funds
|
||||
// If everthing is okay, they will be showing in signers wallet
|
||||
Function Withdraw( amount Uint64) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 SEND_DERO_TO_ADDRESS(SIGNER(),amount)
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// If signer is owner, provide him rights to update code anytime
|
||||
// make sure update is always available to SC
|
||||
Function UpdateCode( code String) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 UPDATE_SC_CODE(code)
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
|
71
tests/specific/lottery_within_block_test/run_test.sh
Executable file
71
tests/specific/lottery_within_block_test/run_test.sh
Executable file
@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#set -x # to enable debug and verbose printing of each and every command
|
||||
|
||||
# this will test case if lottery can run within a block
|
||||
|
||||
CURDIR=`/bin/pwd`
|
||||
BASEDIR=$(dirname $0)
|
||||
ABSPATH=$(readlink -f $0)
|
||||
ABSDIR=$(dirname $ABSPATH)
|
||||
|
||||
command -v curl >/dev/null 2>&1 || { echo "I require curl but it's not installed. Aborting." >&2; exit 1; }
|
||||
command -v jq >/dev/null 2>&1 || { echo "I require jq but it's not installed. Aborting." >&2; exit 1; }
|
||||
|
||||
baseasset="0000000000000000000000000000000000000000000000000000000000000000"
|
||||
|
||||
daemon_rpc_port="20000" # daemon rpc is listening on this port
|
||||
|
||||
# we have number of wallets listening at ports from 30000
|
||||
# we will be using 3 wallets, named owner, player1,player2
|
||||
owner_rpc_port="30000"
|
||||
player1_rpc_port="30001"
|
||||
player2_rpc_port="30002"
|
||||
|
||||
owner_address=$(curl --silent http://127.0.0.1:$owner_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
player1_address=$(curl --silent http://127.0.0.1:$player1_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
player2_address=$(curl --silent http://127.0.0.1:$player2_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json'| jq -r ".result.address")
|
||||
|
||||
|
||||
function balance(){
|
||||
curl --silent http://127.0.0.1:$1/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getbalance"}' -H 'Content-Type: application/json'| jq -r ".result.balance"
|
||||
}
|
||||
|
||||
function scassetbalance(){
|
||||
curl --silent http://127.0.0.1:$daemon_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getsc","params":{ "scid":"'"$1"'" , "code":false, "variables":true}}' -H 'Content-Type: application/json'| jq -r '.result.balances."'$2'"'
|
||||
}
|
||||
|
||||
function mineblock(){
|
||||
touch /dev/shm/mineblocknow
|
||||
}
|
||||
|
||||
echo "SC owner address" $owner_address
|
||||
echo "player1 address" $player1_address
|
||||
echo "player2 address" $player2_address
|
||||
|
||||
|
||||
# use owner wallet to load/install an lotter sc to chain
|
||||
scid=$(curl --silent --request POST --data-binary @test.bas http://127.0.0.1:$owner_rpc_port/install_sc| jq -r ".txid")
|
||||
echo "SCID" $scid
|
||||
mineblock
|
||||
sleep 2
|
||||
|
||||
|
||||
echo -n "2 players playing txid "
|
||||
curl --silent http://127.0.0.1:$player1_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"scinvoke","params":{"sc_dero_deposit":500000,"scid":"'"$scid"'","ringsize":2, "sc_rpc":[{"name":"entrypoint","datatype":"S","value":"Lottery"}] }}' -H 'Content-Type: application/json' | jq -r ".result.txid"
|
||||
curl --silent http://127.0.0.1:$player2_rpc_port/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"scinvoke","params":{"sc_dero_deposit":500000,"scid":"'"$scid"'","ringsize":2, "sc_rpc":[{"name":"entrypoint","datatype":"S","value":"Lottery"}] }}' -H 'Content-Type: application/json' | jq -r ".result.txid"
|
||||
mineblock
|
||||
sleep 4
|
||||
|
||||
echo "SC DERO balance" $(scassetbalance $scid $baseasset )
|
||||
echo "SC owner balance" $(balance $owner_rpc_port)
|
||||
echo "SC player1 balance" $(balance $player1_rpc_port)
|
||||
echo "SC player2 balance" $(balance $player2_rpc_port)
|
||||
|
||||
if [[ $(balance $player1_rpc_port) -gt 1200000 || $(balance $player2_rpc_port) -gt 1200000 ]]
|
||||
then
|
||||
exit 0
|
||||
else
|
||||
echo "test failed"
|
||||
exit 1
|
||||
fi
|
93
tests/specific/lottery_within_block_test/test.bas
Normal file
93
tests/specific/lottery_within_block_test/test.bas
Normal file
@ -0,0 +1,93 @@
|
||||
/* Lottery Smart Contract Example in DVM-BASIC.
|
||||
This lottery smart contract will give lottery wins on every second try in following default contract.
|
||||
Make depost transaction to this SCID to play lottery.
|
||||
Check https://github.com/deroproject/derohe/blob/main/guide/examples/lottery_sc_guide.md
|
||||
*/
|
||||
|
||||
|
||||
|
||||
Function Lottery() Uint64
|
||||
10 dim deposit_count,winner as Uint64
|
||||
20 LET deposit_count = LOAD("deposit_count")+1
|
||||
25 IF DEROVALUE() == 0 THEN GOTO 110 // if deposit amount is 0, simply return
|
||||
30 STORE("depositor_address" + (deposit_count-1), SIGNER()) // store address for later on payment
|
||||
40 STORE("deposit_total", LOAD("deposit_total") + DEROVALUE() )
|
||||
50 STORE("deposit_count",deposit_count)
|
||||
60 IF LOAD("lotteryeveryXdeposit") > deposit_count THEN GOTO 110 // we will wait till X players join in
|
||||
// we are here means all players have joined in, roll the DICE,
|
||||
70 LET winner = RANDOM() % deposit_count // we have a winner
|
||||
80 SEND_DERO_TO_ADDRESS(LOAD("depositor_address" + winner) , LOAD("lotterygiveback")*LOAD("deposit_total")/10000)
|
||||
// Re-Initialize for another round
|
||||
90 STORE("deposit_count", 0) // initial players
|
||||
100 STORE("deposit_total", 0) // total deposit of all players
|
||||
110 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
// This function is used to initialize parameters during install time
|
||||
Function Initialize() Uint64
|
||||
5 version("1.2.3")
|
||||
10 STORE("owner", SIGNER()) // store in DB ["owner"] = address
|
||||
20 STORE("lotteryeveryXdeposit", 2) // lottery will reward every X deposits
|
||||
// How much will lottery giveback in 1/10000 parts, granularity .01 %
|
||||
30 STORE("lotterygiveback", 9900) // lottery will give reward 99% of deposits, 1 % is accumulated for owner to withdraw
|
||||
33 STORE("deposit_count", 0) // initial players
|
||||
34 STORE("deposit_total", 0) // total deposit of all players
|
||||
// 35 printf "Initialize executed"
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
// Function to tune lottery parameters
|
||||
Function TuneLotteryParameters(input Uint64, lotteryeveryXdeposit Uint64, lotterygiveback Uint64) Uint64
|
||||
10 dim key,stored_owner as String
|
||||
20 dim value_uint64 as Uint64
|
||||
30 IF LOAD("owner") == SIGNER() THEN GOTO 100 // check whether owner is real owner
|
||||
40 RETURN 1
|
||||
|
||||
100 STORE("lotteryeveryXdeposit", lotteryeveryXdeposit) // lottery will reward every X deposits
|
||||
130 STORE("lotterygiveback", value_uint64) // how much will lottery giveback in 1/10000 parts, granularity .01 %
|
||||
140 RETURN 0 // return success
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
// This function is used to change owner
|
||||
// owner is an string form of address
|
||||
Function TransferOwnership(newowner String) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 STORE("tmpowner",ADDRESS_RAW(newowner))
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// Until the new owner claims ownership, existing owner remains owner
|
||||
Function ClaimOwnership() Uint64
|
||||
10 IF LOAD("tmpowner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 STORE("owner",SIGNER()) // ownership claim successful
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// If signer is owner, withdraw any requested funds
|
||||
// If everthing is okay, they will be showing in signers wallet
|
||||
Function Withdraw( amount Uint64) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 SEND_DERO_TO_ADDRESS(SIGNER(),amount)
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
// If signer is owner, provide him rights to update code anytime
|
||||
// make sure update is always available to SC
|
||||
Function UpdateCode( code String) Uint64
|
||||
10 IF LOAD("owner") == SIGNER() THEN GOTO 30
|
||||
20 RETURN 1
|
||||
30 UPDATE_SC_CODE(code)
|
||||
40 RETURN 0
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
|
@ -78,7 +78,7 @@ type Transaction_Prefix struct {
|
||||
|
||||
TransactionType TransactionType `json:"txtype"`
|
||||
|
||||
Value uint64 `json:"value"` // represents value for premine, SC, BURN transactions
|
||||
Value uint64 `json:"value"` // represents value for premine, Gas for SC, BURN transactions
|
||||
MinerAddress [33]byte `json:"miner_address"` // miner address // 33 bytes also used for registration
|
||||
C [32]byte `json:"c"` // used for registration
|
||||
S [32]byte `json:"s"` // used for registration
|
||||
@ -226,6 +226,27 @@ func (tx *Transaction) Fees() (fees uint64) {
|
||||
return fees
|
||||
}
|
||||
|
||||
// tx storage gas
|
||||
func (tx *Transaction) GasStorage() (fees uint64) {
|
||||
return tx.Fees()
|
||||
/*
|
||||
if !tx.IsSC(){
|
||||
return 0
|
||||
}
|
||||
var zero_scid [32]byte
|
||||
count := 0
|
||||
for i := range tx.Payloads {
|
||||
if zero_scid == tx.Payloads[i].SCID {
|
||||
count++
|
||||
}
|
||||
}
|
||||
if count == 1 {
|
||||
return tx.Value
|
||||
}
|
||||
return 0
|
||||
*/
|
||||
}
|
||||
|
||||
func (tx *Transaction) IsRegistrationValid() (result bool) {
|
||||
|
||||
var u bn256.G1
|
||||
@ -293,7 +314,7 @@ func (tx *Transaction) Deserialize(buf []byte) (err error) {
|
||||
panic("unknown transaction type")
|
||||
}
|
||||
|
||||
if tx.TransactionType == PREMINE || tx.TransactionType == BURN_TX || tx.TransactionType == SC_TX {
|
||||
if tx.TransactionType == PREMINE || tx.TransactionType == SC_TX { // represents Gas in SC tx
|
||||
tx.Value, done = binary.Uvarint(buf)
|
||||
if done <= 0 {
|
||||
return fmt.Errorf("Invalid Premine value in Transaction\n")
|
||||
@ -420,7 +441,7 @@ func (tx *Transaction) SerializeHeader() []byte {
|
||||
n = binary.PutUvarint(buf, uint64(tx.TransactionType))
|
||||
serialised_header.Write(buf[:n])
|
||||
|
||||
if tx.TransactionType == PREMINE || tx.TransactionType == BURN_TX || tx.TransactionType == SC_TX {
|
||||
if tx.TransactionType == PREMINE || tx.TransactionType == SC_TX {
|
||||
n := binary.PutUvarint(buf, tx.Value)
|
||||
serialised_header.Write(buf[:n])
|
||||
}
|
||||
|
@ -64,15 +64,18 @@ func Transfer(ctx context.Context, p rpc.Transfer_Params) (result rpc.Transfer_R
|
||||
p.SC_RPC = append(p.SC_RPC, rpc.Argument{Name: rpc.SCID, DataType: rpc.DataHash, Value: crypto.HashHexToHash(p.SC_ID)})
|
||||
}
|
||||
|
||||
tx, err := w.wallet.TransferPayload0(p.Transfers, p.Ringsize, false, p.SC_RPC, false)
|
||||
var tx *transaction.Transaction
|
||||
for tries := 0; tries < 2; tries++ {
|
||||
tx, err = w.wallet.TransferPayload0(p.Transfers, p.Ringsize, false, p.SC_RPC, p.Fees, false)
|
||||
if err != nil {
|
||||
w.logger.V(1).Error(err, "Error building tx")
|
||||
return result, err
|
||||
}
|
||||
|
||||
err = w.wallet.SendTransaction(tx)
|
||||
if err != nil {
|
||||
return result, err
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// we must return a txid if everything went alright
|
||||
|
@ -19,7 +19,7 @@ type GenerateProofFunc func(scid crypto.Hash, scid_index int, s *crypto.Statemen
|
||||
var GenerateProoffuncptr GenerateProofFunc = crypto.GenerateProof
|
||||
|
||||
// generate proof etc
|
||||
func (w *Wallet_Memory) BuildTransaction(transfers []rpc.Transfer, emap [][][]byte, rings [][]*bn256.G1, block_hash crypto.Hash, height uint64, scdata rpc.Arguments, roothash []byte, max_bits int) *transaction.Transaction {
|
||||
func (w *Wallet_Memory) BuildTransaction(transfers []rpc.Transfer, emap [][][]byte, rings [][]*bn256.G1, block_hash crypto.Hash, height uint64, scdata rpc.Arguments, roothash []byte, max_bits int, fees uint64) *transaction.Transaction {
|
||||
|
||||
sender := w.account.Keys.Public.G1()
|
||||
sender_secret := w.account.Keys.Secret.BigInt()
|
||||
@ -34,12 +34,7 @@ rebuild_tx:
|
||||
tx.Height = height
|
||||
tx.BLID = block_hash
|
||||
tx.TransactionType = transaction.NORMAL
|
||||
/*
|
||||
if burn_value >= 1 {
|
||||
tx.TransactionType = transaction.BURN_TX
|
||||
tx.Value = burn_value
|
||||
}
|
||||
*/
|
||||
|
||||
if len(scdata) >= 1 {
|
||||
tx.TransactionType = transaction.SC_TX
|
||||
tx.SCDATA = scdata
|
||||
@ -138,15 +133,14 @@ rebuild_tx:
|
||||
asset.SCID = transfers[t].SCID
|
||||
asset.BurnValue = transfers[t].Burn
|
||||
|
||||
fees := uint64(0)
|
||||
value := transfers[t].Amount
|
||||
burn_value := transfers[t].Burn
|
||||
if asset.SCID.IsZero() && !fees_done {
|
||||
fees = uint64(len(transfers)+2) * config.FEE_PER_KB
|
||||
if fees == 0 && asset.SCID.IsZero() && !fees_done {
|
||||
fees = fees + uint64(len(transfers)+2)*config.FEE_PER_KB
|
||||
if data, err := scdata.MarshalBinary(); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
fees = fees + uint64((len(data)/1024)+3)*config.FEE_PER_KB
|
||||
fees = fees + (uint64(len(data))*15)/10
|
||||
}
|
||||
fees_done = true
|
||||
}
|
||||
@ -155,8 +149,14 @@ rebuild_tx:
|
||||
var x bn256.G1
|
||||
switch {
|
||||
case i == witness_index[0]:
|
||||
|
||||
if asset.SCID.IsZero() {
|
||||
x.ScalarMult(crypto.G, new(big.Int).SetInt64(0-int64(value)-int64(fees)-int64(burn_value))) // decrease senders balance
|
||||
} else {
|
||||
x.ScalarMult(crypto.G, new(big.Int).SetInt64(0-int64(value)-int64(burn_value))) // decrease senders balance
|
||||
}
|
||||
//fmt.Printf("sender %d %s \n", i, sender.String())
|
||||
|
||||
case i == witness_index[1]:
|
||||
x.ScalarMult(crypto.G, new(big.Int).SetInt64(int64(value))) // increase receiver's balance
|
||||
//fmt.Printf("receiver %d %s \n",i, receiver.String())
|
||||
@ -217,12 +217,16 @@ rebuild_tx:
|
||||
//fmt.Printf("t %d scid %s balance %d\n", t, transfers[t].SCID, balance)
|
||||
|
||||
// time for bullets-sigma
|
||||
statement := GenerateStatement(CLn, CRn, publickeylist, C, &D, fees) // generate statement
|
||||
fees_currentasset := uint64(0)
|
||||
if asset.SCID.IsZero() {
|
||||
fees_currentasset = fees
|
||||
}
|
||||
statement := GenerateStatement(CLn, CRn, publickeylist, C, &D, fees_currentasset) // generate statement
|
||||
|
||||
copy(statement.Roothash[:], roothash[:])
|
||||
statement.Bytes_per_publickey = byte(max_bits / 8)
|
||||
|
||||
witness := GenerateWitness(sender_secret, r, value, balance-value-fees-burn_value, witness_index)
|
||||
witness := GenerateWitness(sender_secret, r, value, balance-value-fees_currentasset-burn_value, witness_index)
|
||||
|
||||
witness_list = append(witness_list, witness)
|
||||
|
||||
|
@ -218,7 +218,7 @@ func Test_Creation_TX(t *testing.T) {
|
||||
// here we are collecting proofs for later on bennhcmarking
|
||||
for j := 2; j <= 128; j = j * 2 {
|
||||
wsrc.account.Ringsize = j
|
||||
tx, err := wsrc.TransferPayload0([]rpc.Transfer{rpc.Transfer{Destination: wdst.GetAddress().String(), Amount: 1}}, 0, false, rpc.Arguments{}, false)
|
||||
tx, err := wsrc.TransferPayload0([]rpc.Transfer{rpc.Transfer{Destination: wdst.GetAddress().String(), Amount: 1}}, 0, false, rpc.Arguments{}, 0, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot create transaction, err %s", err)
|
||||
} else {
|
||||
@ -236,7 +236,7 @@ func Test_Creation_TX(t *testing.T) {
|
||||
|
||||
// accounts are reversed
|
||||
wdst.Sync_Wallet_Memory_With_Daemon()
|
||||
reverse_tx, err := wdst.TransferPayload0([]rpc.Transfer{rpc.Transfer{Destination: wsrc.GetAddress().String(), Amount: 1}}, 0, false, rpc.Arguments{}, false)
|
||||
reverse_tx, err := wdst.TransferPayload0([]rpc.Transfer{rpc.Transfer{Destination: wsrc.GetAddress().String(), Amount: 1}}, 0, false, rpc.Arguments{}, 0, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot create transaction, err %s", err)
|
||||
}
|
||||
@ -250,7 +250,7 @@ func Test_Creation_TX(t *testing.T) {
|
||||
pre_transfer_src_balance := wsrc.account.Balance_Mature
|
||||
pre_transfer_dst_balance := wdst.account.Balance_Mature
|
||||
|
||||
tx, err := wsrc.TransferPayload0([]rpc.Transfer{rpc.Transfer{Destination: wdst.GetAddress().String(), Amount: 1}}, 0, false, rpc.Arguments{}, false)
|
||||
tx, err := wsrc.TransferPayload0([]rpc.Transfer{rpc.Transfer{Destination: wdst.GetAddress().String(), Amount: 1}}, 0, false, rpc.Arguments{}, 0, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot create transaction, err %s", err)
|
||||
} else {
|
||||
@ -292,7 +292,7 @@ func Test_Creation_TX(t *testing.T) {
|
||||
var tx_set []*transaction.Transaction
|
||||
|
||||
for i := 0; i < 6; i++ {
|
||||
tx, err := wsrc.TransferPayload0([]rpc.Transfer{rpc.Transfer{Destination: wdst.GetAddress().String(), Amount: 1}}, 0, false, rpc.Arguments{}, false)
|
||||
tx, err := wsrc.TransferPayload0([]rpc.Transfer{rpc.Transfer{Destination: wdst.GetAddress().String(), Amount: 1}}, 0, false, rpc.Arguments{}, 0, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot create transaction, err %s", err)
|
||||
} else {
|
||||
|
@ -86,6 +86,10 @@ func Test_Creation_TX_morecheck(t *testing.T) {
|
||||
t.Fatalf("Cannot add regtx to pool err %s", err)
|
||||
}
|
||||
|
||||
simulator_chain_mineblock(chain, wgenesis.GetAddress(), t) // mine a block at tip
|
||||
simulator_chain_mineblock(chain, wgenesis.GetAddress(), t) // mine a block at tip
|
||||
simulator_chain_mineblock(chain, wgenesis.GetAddress(), t) // mine a block at tip
|
||||
simulator_chain_mineblock(chain, wgenesis.GetAddress(), t) // mine a block at tip
|
||||
simulator_chain_mineblock(chain, wgenesis.GetAddress(), t) // mine a block at tip
|
||||
|
||||
wgenesis.SetDaemonAddress(rpcport)
|
||||
@ -102,6 +106,9 @@ func Test_Creation_TX_morecheck(t *testing.T) {
|
||||
if err = wsrc.Sync_Wallet_Memory_With_Daemon(); err != nil {
|
||||
t.Fatalf("wallet sync error err %s", err)
|
||||
}
|
||||
if err = wdst.Sync_Wallet_Memory_With_Daemon(); err != nil {
|
||||
t.Fatalf("wallet sync error err %s", err)
|
||||
}
|
||||
|
||||
wsrc.account.Ringsize = 2
|
||||
wdst.account.Ringsize = 2
|
||||
@ -109,7 +116,12 @@ func Test_Creation_TX_morecheck(t *testing.T) {
|
||||
var txs []transaction.Transaction
|
||||
for i := 0; i < 7; i++ {
|
||||
|
||||
tx, err := wsrc.TransferPayload0([]rpc.Transfer{rpc.Transfer{Destination: wdst.GetAddress().String(), Amount: 700000}}, 0, false, rpc.Arguments{}, false)
|
||||
wsrc.Sync_Wallet_Memory_With_Daemon()
|
||||
wdst.Sync_Wallet_Memory_With_Daemon()
|
||||
|
||||
t.Logf("Chain height %d\n", chain.Get_Height())
|
||||
|
||||
tx, err := wsrc.TransferPayload0([]rpc.Transfer{rpc.Transfer{Destination: wdst.GetAddress().String(), Amount: 700000}}, 0, false, rpc.Arguments{}, 100000, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot create transaction, err %s", err)
|
||||
} else {
|
||||
|
@ -57,7 +57,7 @@ func (w *Wallet_Memory) Transfer_Simplified(addr string, value uint64, data []by
|
||||
// we should reply to an entry
|
||||
|
||||
// send amount to specific addresses
|
||||
func (w *Wallet_Memory) TransferPayload0(transfers []rpc.Transfer, ringsize uint64, transfer_all bool, scdata rpc.Arguments, dry_run bool) (tx *transaction.Transaction, err error) {
|
||||
func (w *Wallet_Memory) TransferPayload0(transfers []rpc.Transfer, ringsize uint64, transfer_all bool, scdata rpc.Arguments, gasstorage uint64, dry_run bool) (tx *transaction.Transaction, err error) {
|
||||
|
||||
// var transfer_details structures.Outgoing_Transfer_Details
|
||||
w.transfer_mutex.Lock()
|
||||
@ -215,6 +215,10 @@ func (w *Wallet_Memory) TransferPayload0(transfers []rpc.Transfer, ringsize uint
|
||||
var block_hash crypto.Hash
|
||||
|
||||
var zeroscid crypto.Hash
|
||||
|
||||
// noncetopo should be verified for all ring members simultaneously
|
||||
// this can lead to tx rejection
|
||||
// we currently bypass this since random members are chosen which have not been used in last 5 block
|
||||
_, noncetopo, block_hash, self_e, err := w.GetEncryptedBalanceAtTopoHeight(zeroscid, -1, w.GetAddress().String())
|
||||
if err != nil {
|
||||
return
|
||||
@ -362,7 +366,7 @@ func (w *Wallet_Memory) TransferPayload0(transfers []rpc.Transfer, ringsize uint
|
||||
max_bits += 6 // extra 6 bits
|
||||
|
||||
if !dry_run {
|
||||
tx = w.BuildTransaction(transfers, rings_balances, rings, block_hash, height, scdata, treehash_raw, max_bits)
|
||||
tx = w.BuildTransaction(transfers, rings_balances, rings, block_hash, height, scdata, treehash_raw, max_bits, gasstorage)
|
||||
}
|
||||
|
||||
if tx == nil {
|
||||
|
Loading…
Reference in New Issue
Block a user