From 75ca9971c98ba923d7211cc75cf364328495e047 Mon Sep 17 00:00:00 2001 From: Captain Date: Sat, 27 Feb 2021 07:47:44 +0000 Subject: [PATCH] DERO-HE STARGATE Testnet Release12 --- blockchain/blockchain.go | 2 +- blockchain/transaction_execute.go | 142 ++++++++++---------- blockchain/transaction_verify.go | 2 +- cmd/derod/rpc_dero_getrandomaddress.go | 2 +- cmd/explorer/explorer.go | 11 +- cmd/explorer/templates.go | 20 ++- config/version.go | 2 +- p2p/controller.go | 12 +- p2p/rpc_object_request.go | 4 +- rpc/wallet_rpc.go | 9 ++ walletapi/rpcserver/rpc_scinvoke.go | 70 ++++++++++ walletapi/rpcserver/rpc_websocket_server.go | 3 +- walletapi/transaction_build.go | 6 +- walletapi/wallet_pool.go | 8 +- walletapi/wallet_transfer.go | 33 ++++- 15 files changed, 235 insertions(+), 91 deletions(-) create mode 100644 walletapi/rpcserver/rpc_scinvoke.go diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go index 7b3a3b6..2783673 100644 --- a/blockchain/blockchain.go +++ b/blockchain/blockchain.go @@ -530,7 +530,7 @@ func (chain *Blockchain) Add_Complete_Block(cbl *block.Complete_Block) (err erro // always check whether the coin base tx is okay if bl.Height != 0 { if err = chain.Verify_Transaction_Coinbase(cbl, &bl.Miner_TX); err != nil { // if miner address is not registered give error - block_logger.Warnf("Error verifying coinbase tx, err :'%s'", err) + //block_logger.Warnf("Error verifying coinbase tx, err :'%s'", err) return err, false } } diff --git a/blockchain/transaction_execute.go b/blockchain/transaction_execute.go index 1e4ecc5..44f351b 100644 --- a/blockchain/transaction_execute.go +++ b/blockchain/transaction_execute.go @@ -200,89 +200,92 @@ func (chain *Blockchain) process_transaction_sc(cache map[crypto.Hash]*graviton. } }() - if tx.SCDATA.Has(rpc.SCACTION, rpc.DataUint64) { // but only it is present - action_code := rpc.SC_ACTION(tx.SCDATA.Value(rpc.SCACTION, rpc.DataUint64).(uint64)) + if !tx.SCDATA.Has(rpc.SCACTION, rpc.DataUint64) { // tx doesn't have sc action + //err = fmt.Errorf("no scid provided") + return tx.Fees(), nil + } - switch action_code { - case rpc.SC_INSTALL: // request to install an SC - if !tx.SCDATA.Has(rpc.SCCODE, rpc.DataString) { // but only it is present - break - } - sc_code := tx.SCDATA.Value(rpc.SCCODE, rpc.DataString).(string) - if sc_code == "" { // no code provided nothing to do - err = fmt.Errorf("no code provided") - break - } + action_code := rpc.SC_ACTION(tx.SCDATA.Value(rpc.SCACTION, rpc.DataUint64).(uint64)) - // check whether sc can be parsed - //var sc_parsed dvm.SmartContract - pos := "" - var sc dvm.SmartContract + switch action_code { + case rpc.SC_INSTALL: // request to install an SC + if !tx.SCDATA.Has(rpc.SCCODE, rpc.DataString) { // but only it is present + break + } + sc_code := tx.SCDATA.Value(rpc.SCCODE, rpc.DataString).(string) + if sc_code == "" { // no code provided nothing to do + err = fmt.Errorf("no code provided") + break + } - sc, pos, err = dvm.ParseSmartContract(sc_code) - if err != nil { - rlog.Warnf("error Parsing sc txid %s err %s pos %s\n", txhash, err, pos) - break - } + // check whether sc can be parsed + //var sc_parsed dvm.SmartContract + pos := "" + var sc dvm.SmartContract - meta := SC_META_DATA{Balance: tx.Value} + sc, pos, err = dvm.ParseSmartContract(sc_code) + if err != nil { + rlog.Warnf("error Parsing sc txid %s err %s pos %s\n", txhash, err, pos) + break + } - if _, ok := sc.Functions["InitializePrivate"]; ok { - meta.Type = 1 - } - if sc_data_tree, err = ss.GetTree(string(scid[:])); err != nil { - break - } else { - w_sc_data_tree = &Tree_Wrapper{tree: sc_data_tree, entries: map[string][]byte{}} - } + meta := SC_META_DATA{Balance: tx.Value} - // 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, Value: sc_code}.MarshalBinaryPanic()) + if _, ok := sc.Functions["InitializePrivate"]; ok { + meta.Type = 1 + } + if sc_data_tree, err = ss.GetTree(string(scid[:])); err != nil { + break + } else { + w_sc_data_tree = &Tree_Wrapper{tree: sc_data_tree, entries: map[string][]byte{}} + } - w_sc_tree.Put(SC_Meta_Key(scid), meta.MarshalBinary()) + // 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, Value: sc_code}.MarshalBinaryPanic()) - // at this point we must trigger the initialize call in the DVM - //fmt.Printf("We must call the SC initialize function\n") + w_sc_tree.Put(SC_Meta_Key(scid), meta.MarshalBinary()) - 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, blid, tx, "InitializePrivate", 1) - } else { - gas, err = chain.execute_sc_function(w_sc_tree, w_sc_data_tree, scid, bl_height, bl_topoheight, blid, tx, "Initialize", 1) - } + // at this point we must trigger the initialize call in the DVM + //fmt.Printf("We must call the SC initialize function\n") - case rpc.SC_CALL: // trigger a CALL - if !tx.SCDATA.Has(rpc.SCID, rpc.DataHash) { // but only it is present - err = fmt.Errorf("no scid provided") - break - } - if !tx.SCDATA.Has("entrypoint", rpc.DataString) { // but only it is present - err = fmt.Errorf("no entrypoint provided") - break - } + 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, blid, tx, "InitializePrivate", 1) + } else { + gas, err = chain.execute_sc_function(w_sc_tree, w_sc_data_tree, scid, bl_height, bl_topoheight, blid, tx, "Initialize", 1) + } - scid = tx.SCDATA.Value(rpc.SCID, rpc.DataHash).(crypto.Hash) + case rpc.SC_CALL: // trigger a CALL + if !tx.SCDATA.Has(rpc.SCID, rpc.DataHash) { // but only it is present + err = fmt.Errorf("no scid provided") + break + } + if !tx.SCDATA.Has("entrypoint", rpc.DataString) { // but only it is present + err = fmt.Errorf("no entrypoint provided") + break + } - if _, err = w_sc_tree.Get(SC_Meta_Key(scid)); err != nil { - err = fmt.Errorf("scid %s not installed", scid) - return - } + scid = tx.SCDATA.Value(rpc.SCID, rpc.DataHash).(crypto.Hash) - if sc_data_tree, err = ss.GetTree(string(scid[:])); err != nil { - - return - } else { - w_sc_data_tree = &Tree_Wrapper{tree: sc_data_tree, entries: map[string][]byte{}} - } - - 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, blid, tx, entrypoint, 1) - - default: // unknown what to do - err = fmt.Errorf("unknown action what to do", scid) + if _, err = w_sc_tree.Get(SC_Meta_Key(scid)); err != nil { + err = fmt.Errorf("scid %s not installed", scid) return } + + if sc_data_tree, err = ss.GetTree(string(scid[:])); err != nil { + + return + } else { + w_sc_data_tree = &Tree_Wrapper{tree: sc_data_tree, entries: map[string][]byte{}} + } + + 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, blid, tx, entrypoint, 1) + + default: // unknown what to do + err = fmt.Errorf("unknown action what to do", scid) + return } if err == nil { // we must commit the changes @@ -323,11 +326,12 @@ func (chain *Blockchain) process_transaction_sc(cache map[crypto.Hash]*graviton. //fmt.Printf("SC %s balance %d\n", scid, w_sc_data_tree.leftover_balance) sc_tree.Put(SC_Meta_Key(scid), meta.MarshalBinary()) - for _, transfer := range w_sc_data_tree.transfere { // give devs reward + for i, transfer := range w_sc_data_tree.transfere { // give devs reward var balance_serialized []byte addr_bytes := []byte(transfer.Address) balance_serialized, err = balance_tree.Get(addr_bytes) if err != nil { + fmt.Printf("%s %d could not transfer %d %+v\n", scid, i, transfer.Amount, addr_bytes) return } balance := new(crypto.ElGamal).Deserialize(balance_serialized) diff --git a/blockchain/transaction_verify.go b/blockchain/transaction_verify.go index a3e0eb7..86f343b 100644 --- a/blockchain/transaction_verify.go +++ b/blockchain/transaction_verify.go @@ -82,7 +82,7 @@ func (chain *Blockchain) Verify_Transaction_Coinbase(cbl *block.Complete_Block, _, topos := chain.Store.Topo_store.binarySearchHeight(int64(cbl.Bl.Height - 1)) // load all db versions one by one and check whether the root hash matches the one mentioned in the tx if len(topos) < 1 { - return fmt.Errorf("could not find previous height blocks") + return fmt.Errorf("could not find previous height blocks %d", cbl.Bl.Height-1) } var balance_tree *graviton.Tree diff --git a/cmd/derod/rpc_dero_getrandomaddress.go b/cmd/derod/rpc_dero_getrandomaddress.go index a00769a..27dfffc 100644 --- a/cmd/derod/rpc_dero_getrandomaddress.go +++ b/cmd/derod/rpc_dero_getrandomaddress.go @@ -53,7 +53,7 @@ func (DERO_RPC_APIS) GetRandomAddress(ctx context.Context, p rpc.GetRandomAddres } treename := config.BALANCE_TREE - if p.SCID.IsZero() { + if !p.SCID.IsZero() { treename = string(p.SCID[:]) } diff --git a/cmd/explorer/explorer.go b/cmd/explorer/explorer.go index c27d503..8f3aa71 100644 --- a/cmd/explorer/explorer.go +++ b/cmd/explorer/explorer.go @@ -289,7 +289,7 @@ type txinfo struct { } type Asset struct { - SCID crypto.Hash + SCID string Fees string Burn string Ring []string @@ -561,9 +561,14 @@ func load_tx_from_rpc(info *txinfo, txhash string) (err error) { for t := range tx.Payloads { var a Asset - a.SCID = tx.Payloads[t].SCID + a.SCID = tx.Payloads[t].SCID.String() a.Fees = fmt.Sprintf("%.05f", float64(tx.Payloads[t].Statement.Fees)/100000) a.Burn = fmt.Sprintf("%.05f", float64(tx.Payloads[t].BurnValue)/100000) + + if len(tx_result.Txs[0].Ring) == 0 { + continue + } + a.Ring_size = len(tx_result.Txs[0].Ring[t]) for i := range tx_result.Txs[0].Ring[t] { @@ -772,7 +777,7 @@ func show_page(w http.ResponseWriter, page int) { } - fmt.Printf("page %+v\n", data) + //fmt.Printf("page %+v\n", data) err = t.ExecuteTemplate(w, "main", data) if err != nil { diff --git a/cmd/explorer/templates.go b/cmd/explorer/templates.go index 2fcb59b..276e05c 100644 --- a/cmd/explorer/templates.go +++ b/cmd/explorer/templates.go @@ -365,8 +365,26 @@ var tx_template string = `{{define "tx"}} {{range $ii, $ee := .info.Assets}} -
SCID: {{$ee.SCID}} {{$ee.Ring_size}} inputs/outputs (RING size) Fees {{$ee.Fees}} Burned {{$ee.Burn}}
+ {{if eq $ee.SCID "0000000000000000000000000000000000000000000000000000000000000000" }} +
DERO : {{$ee.Ring_size}} inputs/outputs (RING size) Fees {{$ee.Fees}} + {{if eq $.info.TransactionType "SC"}} + Deposited to SC {{$ee.Burn}} + {{else}} + Burned {{$ee.Burn}} + {{end}} + +
+ + {{else}} +
SCID: {{$ee.SCID}} {{$ee.Ring_size}} inputs/outputs (RING size) Fees {{$ee.Fees}} {{if eq $.info.TransactionType "SC"}} + Deposited Tokens to SC {{$ee.Burn}} + {{else}} + Burned {{$ee.Burn}} + {{end}} + +
+ {{end}}
diff --git a/config/version.go b/config/version.go index 1a15628..e8220bb 100644 --- a/config/version.go +++ b/config/version.go @@ -20,4 +20,4 @@ import "github.com/blang/semver" // right now it has to be manually changed // do we need to include git commitsha?? -var Version = semver.MustParse("3.2.0-16.DEROHE.STARGATE+23022021") +var Version = semver.MustParse("3.2.12-1.DEROHE.STARGATE+27022021") diff --git a/p2p/controller.go b/p2p/controller.go index 66090dc..da0f54b 100644 --- a/p2p/controller.go +++ b/p2p/controller.go @@ -412,12 +412,12 @@ func process_connection(conn net.Conn, remote_addr *net.TCPAddr, incoming, sync_ } go func() { //defer globals.Recover() - defer func() { - if r := recover(); r != nil { - rlog.Warnf("Recovered while handling connection, Stack trace below", r) - rlog.Warnf("Stack trace \n%s", debug.Stack()) - } - }() + defer func() { + if r := recover(); r != nil { + rlog.Warnf("Recovered while handling connection, Stack trace below", r) + rlog.Warnf("Stack trace \n%s", debug.Stack()) + } + }() //RPCSERVER.ServeConn(rconn.ServerConn) // start single threaded rpc server with GOB encoding RPCSERVER.ServeCodec(NewCBORServerCodec(rconn.ServerConn)) // use CBOR encoding on rpc }() diff --git a/p2p/rpc_object_request.go b/p2p/rpc_object_request.go index a600fa3..41bafee 100644 --- a/p2p/rpc_object_request.go +++ b/p2p/rpc_object_request.go @@ -34,8 +34,8 @@ func (connection *Connection) GetObject(request ObjectList, response *Objects) e for i := range request.Block_list { // find the block var cbl Complete_Block bl, err := chain.Load_BL_FROM_ID(request.Block_list[i]) - if err != nil{ - return err + if err != nil { + return err } cbl.Block = bl.Serialize() for j := range bl.Tx_hashes { diff --git a/rpc/wallet_rpc.go b/rpc/wallet_rpc.go index 4e76127..1649b65 100644 --- a/rpc/wallet_rpc.go +++ b/rpc/wallet_rpc.go @@ -205,6 +205,15 @@ type ( } ) +type ( + SC_Invoke_Params struct { + SC_ID string `json:"scid"` + SC_RPC Arguments `json:"sc_rpc"` + SC_DERO_Deposit uint64 `json:"sc_dero_deposit"` + SC_TOKEN_Deposit uint64 `json:"sc_token_deposit"` + } +) + type ( Get_Transfers_Params struct { Coinbase bool `json:"coinbase"` diff --git a/walletapi/rpcserver/rpc_scinvoke.go b/walletapi/rpcserver/rpc_scinvoke.go new file mode 100644 index 0000000..8e2e1af --- /dev/null +++ b/walletapi/rpcserver/rpc_scinvoke.go @@ -0,0 +1,70 @@ +// 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 rpcserver + +import "fmt" + +import "context" +import "runtime/debug" +import "github.com/romana/rlog" +import "github.com/deroproject/derohe/rpc" +import "github.com/deroproject/derohe/cryptography/crypto" + +func (w *WALLET_RPC_APIS) ScInvoke(ctx context.Context, p rpc.SC_Invoke_Params) (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 %s", debug.Stack()) + } + }() + + rlog.Debugf("ScInvoke handler") + defer rlog.Debugf("ScInvoke handler finished") + + if !w.wallet.GetMode() { // if wallet is in online mode, use the fees, provided by the daemon, else we need to use what is provided by the user + return fmt.Errorf("Wallet is in offline mode") + } + + // translate rpc to arguments + + //fmt.Printf("incoming transfer params %+v\n", p) + + if p.SC_ID == "" { + return fmt.Errorf("SCID cannot be empty") + } + + // if destination is "", we will choose a random address automatically + + var tp rpc.Transfer_Params + tp.Transfers = append(tp.Transfers, rpc.Transfer{Destination: "deto1qxsplx7vzgydacczw6vnrtfh3fxqcjevyxcvlvl82fs8uykjkmaxgfgulfha5", Amount: 0, Burn: p.SC_DERO_Deposit}) + + // we must burn this much tokens + if p.SC_TOKEN_Deposit >= 1 { + scid := crypto.HashHexToHash(p.SC_ID) + tp.Transfers = append(tp.Transfers, rpc.Transfer{SCID: scid, Amount: 0, Burn: p.SC_TOKEN_Deposit}) + } + tp.SC_RPC = p.SC_RPC + tp.SC_ID = p.SC_ID + + //fmt.Printf("transfers %+v\n", tp) + + err = wallet_apis.Transfer(context.Background(), tp) + + //fmt.Printf("err transfer %s\n", err) + + return err + +} diff --git a/walletapi/rpcserver/rpc_websocket_server.go b/walletapi/rpcserver/rpc_websocket_server.go index d5c6edc..6b48d4c 100644 --- a/walletapi/rpcserver/rpc_websocket_server.go +++ b/walletapi/rpcserver/rpc_websocket_server.go @@ -148,7 +148,7 @@ func (r *RPCServer) Run(wallet *walletapi.Wallet_Disk) { } p.SC_Code = string(b) // encode as base64 - p.Transfers = append(p.Transfers, rpc.Transfer{Destination: "deto1qxsplx7vzgydacczw6vnrtfh3fxqcjevyxcvlvl82fs8uykjkmaxgfgulfha5", Amount: 1}) + p.Transfers = append(p.Transfers, rpc.Transfer{Destination: "deto1qxsplx7vzgydacczw6vnrtfh3fxqcjevyxcvlvl82fs8uykjkmaxgfgulfha5", Amount: 0}) if err := wallet_apis.Transfer(context.Background(), p); err != nil { fmt.Fprintf(w, err.Error()) return @@ -281,6 +281,7 @@ var historical_apis = handler.Map{ "transfer": handler.New(wallet_apis.Transfer), "Transfer": handler.New(wallet_apis.Transfer), "transfer_split": handler.New(wallet_apis.Transfer), + "scinvoke": handler.New(wallet_apis.ScInvoke), } func translate_http_to_jsonrpc_and_vice_versa(w http.ResponseWriter, r *http.Request) { diff --git a/walletapi/transaction_build.go b/walletapi/transaction_build.go index a6311c9..1a05f0f 100644 --- a/walletapi/transaction_build.go +++ b/walletapi/transaction_build.go @@ -113,10 +113,12 @@ func (w *Wallet_Memory) BuildTransaction(transfers []rpc.Transfer, emap map[stri asset.SCID = transfers[t].SCID asset.BurnValue = transfers[t].Burn - fees := uint64(1) + fees := uint64(0) value := transfers[t].Amount burn_value := transfers[t].Burn - + if asset.SCID.IsZero() && (value+burn_value) == 0 { + fees = 1 + } for i := range publickeylist { // setup commitments var x bn256.G1 switch { diff --git a/walletapi/wallet_pool.go b/walletapi/wallet_pool.go index 0412164..b667e6f 100644 --- a/walletapi/wallet_pool.go +++ b/walletapi/wallet_pool.go @@ -79,6 +79,9 @@ func (w Wallet_Pool_Entry) DeepCopy() (r Wallet_Pool_Entry) { func (w Wallet_Pool_Entry) Amount() (v uint64) { for i := range w.Transfers { v += w.Transfers[i].Amount + if w.Transfers[i].SCID.IsZero() { + v += w.Transfers[i].Burn + } } return v @@ -127,13 +130,16 @@ func (w *Wallet_Memory) PoolTransfer(transfers []rpc.Transfer, scdata rpc.Argume } // total which is pending to be sent +// what about SCID, how to show their balance func (w *Wallet_Memory) PoolBalance() (balance uint64) { w.account.Lock() defer w.account.Unlock() for i := range w.account.Pool { for j := range w.account.Pool[i].Transfers { - balance += w.account.Pool[i].Transfers[j].Amount //+ w.account.Pool[i].Burn + if w.account.Pool[i].Transfers[j].SCID.IsZero() { + balance += w.account.Pool[i].Transfers[j].Amount + w.account.Pool[i].Transfers[j].Burn + } } } return diff --git a/walletapi/wallet_transfer.go b/walletapi/wallet_transfer.go index e98a209..514ea78 100644 --- a/walletapi/wallet_transfer.go +++ b/walletapi/wallet_transfer.go @@ -111,8 +111,36 @@ func (w *Wallet_Memory) TransferPayload0(transfers []rpc.Transfer, transfer_all return } - for i := range transfers { - if _, err = rpc.NewAddress(transfers[i].Destination); err != nil { + for t := range transfers { + saddress := transfers[t].Destination + + if saddress == "" { // user skipped destination + if transfers[t].SCID.IsZero() { + err = fmt.Errorf("Main Destination cannot be empty") + return + } + + // we will try 5 times, to get a random ring ring member other than us, if ok, we move ahead + for i := 0; i < 5; i++ { + for _, k := range w.random_ring_members(transfers[t].SCID) { + + //fmt.Printf("%d ring %d '%s'\n",i,j,k) + if k != w.GetAddress().String() { + saddress = k + transfers[t].Destination = k + i = 1000 // break outer loop also + break + } + } + } + } + + if saddress == "" { + err = fmt.Errorf("could not obtain random ring member for scid %s", transfers[t].SCID) + return + } + if _, err = rpc.NewAddress(saddress); err != nil { + fmt.Printf("err processing address '%s' err '%s'\n", saddress, err) return } } @@ -174,6 +202,7 @@ func (w *Wallet_Memory) TransferPayload0(transfers []rpc.Transfer, transfer_all var dest_e *crypto.ElGamal bits_needed[1], dest_e, err = w.GetEncryptedBalanceAtTopoHeight(transfers[t].SCID, -1, addr.String()) if err != nil { + fmt.Printf(" t %d unregistered1 '%s' %s\n", t, addr, err) return } else { emap[string(transfers[t].SCID.String())][addr.PublicKey.G1().String()] = dest_e.Serialize()