diff --git a/apis/eth_price.go b/apis/eth_price.go index ffd8c1eb..f7e82947 100644 --- a/apis/eth_price.go +++ b/apis/eth_price.go @@ -4,11 +4,12 @@ import ( "bytes" "encoding/json" "fmt" - "github.com/golang/glog" - "github.com/montanaflynn/stats" "io/ioutil" "net/http" "strconv" + + "github.com/golang/glog" + "github.com/montanaflynn/stats" ) type CoinbaseResponse struct { @@ -194,7 +195,7 @@ func GetUSDToETHPrice() (float64, error) { amount, err := getCoinbasePrice() if err != nil { // The amount will be zero in this case, which is fine - glog.Errorf("Error fetching Coinbase price: %v", err) + glog.V(2).Infof("Error fetching Coinbase price: %v", err) } if amount != 0 { @@ -205,7 +206,7 @@ func GetUSDToETHPrice() (float64, error) { amount, err := getCoingeckoPrice() if err != nil { // The amount will be zero in this case, which is fine - glog.Errorf("Error fetching Coingecko price: %v", err) + glog.V(2).Infof("Error fetching Coingecko price: %v", err) } if amount != 0 { @@ -216,7 +217,7 @@ func GetUSDToETHPrice() (float64, error) { amount, err := getBlockchainDotcomPrice() if err != nil { // The amount will be zero in this case, which is fine - glog.Errorf("Error fetching blockchain.com price: %v", err) + glog.V(2).Infof("Error fetching blockchain.com price: %v", err) } if amount != 0 { @@ -227,7 +228,7 @@ func GetUSDToETHPrice() (float64, error) { amount, err := getGeminiPrice() if err != nil { // The amount will be zero in this case, which is fine - glog.Errorf("Error fetching Gemini price: %v", err) + glog.V(2).Infof("Error fetching Gemini price: %v", err) } if amount != 0 { @@ -238,7 +239,7 @@ func GetUSDToETHPrice() (float64, error) { amount, err := getKrakenPrice() if err != nil { // The amount will be zero in this case, which is fine - glog.Errorf("Error fetching Kraken price: %v", err) + glog.V(2).Infof("Error fetching Kraken price: %v", err) } if amount != 0 { diff --git a/routes/admin_fees.go b/routes/admin_fees.go index 52eebe7f..d8c64829 100644 --- a/routes/admin_fees.go +++ b/routes/admin_fees.go @@ -255,7 +255,7 @@ func (fes *APIServer) GetTransactionFeeMapFromGlobalState() map[lib.TxnType][]*l var feeOutputs []*lib.DeSoOutput // Decode the bytes into the slice of DeSoOutputs if err = gob.NewDecoder(bytes.NewReader(desoOutputBytes)).Decode(&feeOutputs); err != nil { - glog.Infof("Error decoding desoOutputBytes to slice of DeSoOutputs: %v - default to no additional fees", err) + glog.V(2).Infof("Error decoding desoOutputBytes to slice of DeSoOutputs: %v - default to no additional fees", err) // Default to an empty slice. transactionFeeMap[txnType] = []*lib.DeSoOutput{} } else { diff --git a/routes/admin_node.go b/routes/admin_node.go index 473c26dd..21692b7c 100644 --- a/routes/admin_node.go +++ b/routes/admin_node.go @@ -167,7 +167,7 @@ func (fes *APIServer) _handleNodeControlGetInfo( existingDeSoPeers[currentPeerRes.IP+fmt.Sprintf(":%d", currentPeerRes.ProtocolPort)] = true } // Return some deso addrs from the addr manager. - desoAddrs := fes.backendServer.GetConnectionManager().GetAddrManager().AddressCache() + desoAddrs := fes.backendServer.AddrMgr.AddressCache() sort.Slice(desoAddrs, func(ii, jj int) bool { // Use a hash to get a random but deterministic ordering. hashI := string(lib.Sha256DoubleHash([]byte(desoAddrs[ii].IP.String() + fmt.Sprintf(":%d", desoAddrs[ii].Port)))[:]) @@ -239,12 +239,12 @@ func (fes *APIServer) _handleConnectDeSoNode( // increasing retry delay, but we should still clean it up at some point. connectPeerDone := make(chan bool) go func() { - netAddr, err := fes.backendServer.GetConnectionManager().GetAddrManager().HostToNetAddress(ip, protocolPort, 0) + netAddr, err := fes.backendServer.AddrMgr.HostToNetAddress(ip, protocolPort, 0) if err != nil { _AddBadRequestError(ww, fmt.Sprintf("_handleConnectDeSoNode: Cannot connect to node %s:%d: %v", ip, protocolPort, err)) return } - fes.backendServer.GetConnectionManager().ConnectPeer(nil, netAddr) + fes.backendServer.GetNetworkManager().CreateNonValidatorOutboundConnection(ip) // Spin until the peer shows up in the connection manager or until 100 iterations. // Note the pause between each iteration. @@ -274,7 +274,7 @@ func (fes *APIServer) _handleConnectDeSoNode( // At this point the peer shoud be connected. Add their address to the addrmgr // in case the user wants to connect again in the future. Set the source to be // the address itself since we don't have anything else. - fes.backendServer.GetConnectionManager().GetAddrManager().AddAddress(netAddr, netAddr) + fes.backendServer.AddrMgr.AddAddress(netAddr, netAddr) connectPeerDone <- true return @@ -320,13 +320,13 @@ func (fes *APIServer) _handleDisconnectDeSoNode( // Manually remove the peer from the connection manager and mark it as such // so that the connection manager won't reconnect to it or replace it. - fes.backendServer.GetConnectionManager().RemovePeer(peerFound) - peerFound.PeerManuallyRemovedFromConnectionManager = true - - peerFound.Disconnect() + remoteNode := fes.backendServer.GetNetworkManager().GetRemoteNodeFromPeer(peerFound) + if remoteNode != nil { + fes.backendServer.GetNetworkManager().Disconnect(remoteNode) + } res := NodeControlResponse{ - // Return an empty response, which indicates we set the peer up to be connected. + // Return an empty response, which indicates we set the peer up to be disconnected. } if err := json.NewEncoder(ww).Encode(res); err != nil { _AddBadRequestError(ww, fmt.Sprintf("NodeControl: Problem encoding response as JSON: %v", err)) diff --git a/routes/admin_transaction_test.go b/routes/admin_transaction_test.go index 869a182d..20ecfd4d 100644 --- a/routes/admin_transaction_test.go +++ b/routes/admin_transaction_test.go @@ -91,7 +91,7 @@ func TestUpdateGlobalParams(t *testing.T) { require.Equal(t, globalParams.ValidatorJailEpochDuration, uint64(3)) require.Equal(t, globalParams.LeaderScheduleMaxNumValidators, uint64(100)) require.Equal(t, globalParams.EpochDurationNumBlocks, uint64(10)) - require.Equal(t, globalParams.JailInactiveValidatorGracePeriodEpochs, uint64(48)) + require.Equal(t, globalParams.JailInactiveValidatorGracePeriodEpochs, uint64(3)) } { // Update all GlobalParam fields. diff --git a/routes/base.go b/routes/base.go index fa72279c..ce0359a0 100644 --- a/routes/base.go +++ b/routes/base.go @@ -150,14 +150,14 @@ func (fes *APIServer) GetBlockchainDotComExchangeRate() (_exchangeRate float64, url := "https://api.blockchain.com/v3/exchange/tickers/CLOUT-USD" req, err := http.NewRequest("GET", url, nil) if err != nil { - glog.Errorf("GetBlockchainDotComExchangeRate: Problem creating request: %v", err) + glog.V(2).Infof("GetBlockchainDotComExchangeRate: Problem creating request: %v", err) continue } req.Header.Set("Content-Type", "application/json") resp, err := httpClient.Do(req) if err != nil { - glog.Errorf("GetBlockchainDotComExchangeRate: Problem with HTTP request %s: %v", url, err) + glog.V(2).Infof("GetBlockchainDotComExchangeRate: Problem with HTTP request %s: %v", url, err) continue } defer resp.Body.Close() @@ -167,7 +167,7 @@ func (fes *APIServer) GetBlockchainDotComExchangeRate() (_exchangeRate float64, responseData := &BlockchainDeSoTickerResponse{} decoder := json.NewDecoder(bytes.NewReader(body)) if err = decoder.Decode(responseData); err != nil { - glog.Errorf("GetBlockchainDotComExchangeRate: Problem decoding response JSON into "+ + glog.V(2).Infof("GetBlockchainDotComExchangeRate: Problem decoding response JSON into "+ "interface %v, response: %v, error: %v", responseData, resp, err) continue } @@ -179,13 +179,13 @@ func (fes *APIServer) GetBlockchainDotComExchangeRate() (_exchangeRate float64, } blockchainDotComExchangeRate, err := stats.Max(exchangeRatesFetched) if err != nil { - glog.Errorf("GetBlockchainDotComExchangeRate: Problem getting max from list of float64s: %v", err) + glog.V(2).Infof("GetBlockchainDotComExchangeRate: Problem getting max from list of float64s: %v", err) return 0, err } glog.V(2).Infof("Blockchain exchange rate: %v %v", blockchainDotComExchangeRate, exchangeRatesFetched) if fes.backendServer != nil && fes.backendServer.GetStatsdClient() != nil { if err = fes.backendServer.GetStatsdClient().Gauge("BLOCKCHAIN_LAST_TRADE_PRICE", blockchainDotComExchangeRate, []string{}, 1); err != nil { - glog.Errorf("GetBlockchainDotComExchangeRate: Error logging Last Trade Price of %f to datadog: %v", blockchainDotComExchangeRate, err) + glog.V(2).Infof("GetBlockchainDotComExchangeRate: Error logging Last Trade Price of %f to datadog: %v", blockchainDotComExchangeRate, err) } } return blockchainDotComExchangeRate, nil diff --git a/routes/bitcoin_price.go b/routes/bitcoin_price.go index 5f7842ee..31f8e2d6 100644 --- a/routes/bitcoin_price.go +++ b/routes/bitcoin_price.go @@ -4,11 +4,12 @@ import ( "bytes" "encoding/json" "fmt" - "github.com/golang/glog" - "github.com/montanaflynn/stats" "io/ioutil" "net/http" "strconv" + + "github.com/golang/glog" + "github.com/montanaflynn/stats" ) type CoinbaseResponse struct { @@ -206,7 +207,7 @@ func GetUSDToBTCPrice() (float64, error) { amount, err := getCoinbasePrice() if err != nil { // The amount will be zero in this case, which is fine - glog.Errorf("Error fetching Coinbase price: %v", err) + glog.V(2).Infof("Error fetching Coinbase price: %v", err) } if amount != 0 { @@ -217,7 +218,7 @@ func GetUSDToBTCPrice() (float64, error) { amount, err := getCoingeckoPrice() if err != nil { // The amount will be zero in this case, which is fine - glog.Errorf("Error fetching Coingecko price: %v", err) + glog.V(2).Infof("Error fetching Coingecko price: %v", err) } if amount != 0 { @@ -228,7 +229,7 @@ func GetUSDToBTCPrice() (float64, error) { amount, err := getBlockchainDotcomPrice() if err != nil { // The amount will be zero in this case, which is fine - glog.Errorf("Error fetching blockchain.com price: %v", err) + glog.V(2).Infof("Error fetching blockchain.com price: %v", err) } if amount != 0 { @@ -239,7 +240,7 @@ func GetUSDToBTCPrice() (float64, error) { amount, err := getGeminiPrice() if err != nil { // The amount will be zero in this case, which is fine - glog.Errorf("Error fetching Gemini price: %v", err) + glog.V(2).Infof("Error fetching Gemini price: %v", err) } if amount != 0 { @@ -250,7 +251,7 @@ func GetUSDToBTCPrice() (float64, error) { amount, err := getKrakenPrice() if err != nil { // The amount will be zero in this case, which is fine - glog.Errorf("Error fetching Kraken price: %v", err) + glog.V(2).Infof("Error fetching Kraken price: %v", err) } if amount != 0 { diff --git a/routes/hot_feed.go b/routes/hot_feed.go index 9a884efa..9c1b127a 100644 --- a/routes/hot_feed.go +++ b/routes/hot_feed.go @@ -109,9 +109,9 @@ func (fes *APIServer) StartHotFeedRoutine() { // The business. func (fes *APIServer) UpdateHotFeed(resetCache bool) { - glog.Info("Refreshing hot feed...") + glog.V(2).Info("Refreshing hot feed...") if resetCache { - glog.Info("Resetting hot feed cache.") + glog.V(2).Info("Resetting hot feed cache.") fes.PostTagToPostHashesMap = make(map[string]map[lib.BlockHash]bool) fes.PostHashToPostTagsMap = make(map[lib.BlockHash][]string) fes.HotFeedBlockCache = make(map[lib.BlockHash]*lib.MsgDeSoBlock) @@ -137,7 +137,7 @@ func (fes *APIServer) UpdateHotFeed(resetCache bool) { // Replace the HotFeedApprovedPostsMap and HotFeedPKIDMultiplier map with the fresh ones. fes.HotFeedApprovedPostsToMultipliers = hotFeedApprovedPosts fes.HotFeedPKIDMultipliers = hotFeedPKIDMultipliers - glog.Infof("Updated hot feed maps") + glog.V(2).Infof("Updated hot feed maps") } func (fes *APIServer) UpdateHotFeedApprovedPostsMap(hotFeedApprovedPosts map[lib.BlockHash]float64) { @@ -412,7 +412,7 @@ func (fes *APIServer) UpdateHotFeedOrderedList( } // Log how long this routine takes, since it could be heavy. - glog.Info("UpdateHotFeedOrderedList: Starting new update cycle.") + glog.V(2).Info("UpdateHotFeedOrderedList: Starting new update cycle.") start := time.Now() // Get a utxoView for lookups. diff --git a/routes/server.go b/routes/server.go index e5531599..2a90dd2f 100644 --- a/routes/server.go +++ b/routes/server.go @@ -68,6 +68,7 @@ const ( RoutePathAppendExtraData = "/api/v0/append-extra-data" RoutePathGetTransactionSpending = "/api/v0/get-transaction-spending" RoutePathGetSignatureIndex = "/api/v0/signature-index" + RoutePathGetTxnConstructionParams = "/api/v0/txn-construction-params" RoutePathGetUsersStateless = "/api/v0/get-users-stateless" RoutePathDeleteIdentities = "/api/v0/delete-identities" @@ -1024,6 +1025,13 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { fes.GetSignatureIndex, PublicAccess, }, + { + "GetTxnConstructionParams", + []string{"POST", "OPTIONS"}, + RoutePathGetTxnConstructionParams, + fes.GetTxnConstructionParams, + PublicAccess, + }, { "GetNotifications", []string{"POST", "OPTIONS"}, diff --git a/routes/transaction.go b/routes/transaction.go index 7bf7c1e8..026ed68e 100644 --- a/routes/transaction.go +++ b/routes/transaction.go @@ -4198,3 +4198,74 @@ func (fes *APIServer) GetSignatureIndex(ww http.ResponseWriter, req *http.Reques } return } + +type GetTxnConstructionParamsRequest struct { + MinFeeRateNanosPerKB uint64 + MempoolCongestionFactorBasisPoints uint64 + MempoolPriorityPercentileBasisPoints uint64 + PastBlocksCongestionFactorBasisPoints uint64 + PastBlocksPriorityPercentileBasisPoints uint64 + MaxBlockSize uint64 +} + +type GetTxnConstructionParamsResponse struct { + FeeRateNanosPerKB uint64 + BlockHeight uint64 +} + +func (fes *APIServer) GetTxnConstructionParams(ww http.ResponseWriter, req *http.Request) { + decoder := json.NewDecoder(req.Body) + requestData := GetTxnConstructionParamsRequest{} + if err := decoder.Decode(&requestData); err != nil { + _AddBadRequestError(ww, "GetTxnConstructionParams: Problem parsing request body: "+err.Error()) + return + } + + // TODO: replace lib.MaxBasisPoints w/ a param defined by a flag from core. + mempoolCongestionFactorBasisPoints := requestData.MempoolCongestionFactorBasisPoints + if requestData.MempoolCongestionFactorBasisPoints == 0 { + mempoolCongestionFactorBasisPoints = lib.MaxBasisPoints + } + + mempoolPriorityPercentileBasisPoints := requestData.MempoolPriorityPercentileBasisPoints + if requestData.MempoolPriorityPercentileBasisPoints == 0 { + mempoolPriorityPercentileBasisPoints = lib.MaxBasisPoints + } + + pastBlocksCongestionFactorBasisPoints := requestData.PastBlocksCongestionFactorBasisPoints + if requestData.PastBlocksCongestionFactorBasisPoints == 0 { + pastBlocksCongestionFactorBasisPoints = lib.MaxBasisPoints + } + + pastBlocksPriorityPercentileBasisPoints := requestData.PastBlocksPriorityPercentileBasisPoints + if requestData.PastBlocksPriorityPercentileBasisPoints == 0 { + pastBlocksPriorityPercentileBasisPoints = lib.MaxBasisPoints + } + + maxBlockSize := requestData.MaxBlockSize + if requestData.MaxBlockSize == 0 { + maxBlockSize = fes.Params.MaxBlockSizeBytes + } + + // Get the fees from the mempool + feeRate, err := fes.backendServer.GetMempool().EstimateFeeRate( + requestData.MinFeeRateNanosPerKB, + mempoolCongestionFactorBasisPoints, + mempoolPriorityPercentileBasisPoints, + pastBlocksCongestionFactorBasisPoints, + pastBlocksPriorityPercentileBasisPoints, + maxBlockSize, + ) + if err != nil { + _AddBadRequestError(ww, "GetTxnConstructionParams: Problem getting fees: "+err.Error()) + return + } + // Return the fees + if err = json.NewEncoder(ww).Encode(GetTxnConstructionParamsResponse{ + FeeRateNanosPerKB: feeRate, + BlockHeight: uint64(fes.backendServer.GetBlockchain().BlockTip().Height), + }); err != nil { + _AddBadRequestError(ww, "GetTxnConstructionParams: Problem encoding response as JSON: "+err.Error()) + return + } +} diff --git a/routes/verify.go b/routes/verify.go index e668b593..9c9910eb 100644 --- a/routes/verify.go +++ b/routes/verify.go @@ -1469,6 +1469,9 @@ func (fes *APIServer) SetJumioUSDCents() { glog.Errorf("SetJumioUSDCents: Error getting Jumio USD Cents from global state: %v", err) return } + if len(val) == 0 { + return + } jumioUSDCents, bytesRead := lib.Uvarint(val) if bytesRead <= 0 { glog.Errorf("SetJumioUSDCents: invalid bytes read: %v", bytesRead) @@ -1487,6 +1490,9 @@ func (fes *APIServer) SetJumioKickbackUSDCents() { glog.Errorf("SetJumioKickbackUSDCents: Error getting Jumio Kickback USD Cents from global state: %v", err) return } + if len(val) == 0 { + return + } jumioKickbackUSDCents, bytesRead := lib.Uvarint(val) if bytesRead <= 0 { glog.Errorf("SetJumioKickbackUSDCents: invalid bytes read: %v", bytesRead) diff --git a/scripts/pos/validator_registration.go b/scripts/pos/validator_registration.go new file mode 100644 index 00000000..cbe79499 --- /dev/null +++ b/scripts/pos/validator_registration.go @@ -0,0 +1,198 @@ +package main + +import ( + "bytes" + "encoding/hex" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "time" + + "github.com/btcsuite/btcd/btcec" + "github.com/deso-protocol/backend/routes" + "github.com/deso-protocol/core/bls" + "github.com/deso-protocol/core/lib" + "github.com/holiman/uint256" + "github.com/pkg/errors" + "github.com/tyler-smith/go-bip39" +) + +var desoSourceSeedPhrase = "" +var validatorSeedPhrase = "SEED PHRASE HERE" +var nodeApiUrl = "http://localhost:18001" +var validatorDomain string = "localhost:19000" + +var params = &lib.DeSoTestnetParams + +func getBLSVotingAuthorizationAndPublicKey(blsKeyStore *lib.BLSKeystore, transactorPublicKey *lib.PublicKey) ( + *bls.PublicKey, *bls.Signature, +) { + votingAuthPayload := lib.CreateValidatorVotingAuthorizationPayload(transactorPublicKey.ToBytes()) + votingAuthorization, err := blsKeyStore.GetSigner().Sign(votingAuthPayload) + if err != nil { + panic(err) + } + return blsKeyStore.GetSigner().GetPublicKey(), votingAuthorization +} + +func makePostRequest[TPayload any, TResponse any](url string, payload TPayload) TResponse { + postBody, err := json.Marshal(payload) + if err != nil { + panic(errors.Wrap(err, "main(): Could not complete request")) + } + postBuffer := bytes.NewBuffer(postBody) + + // Execute request. + resp, err := http.Post(url, "application/json", postBuffer) + if err != nil { + panic(errors.Wrap(err, "main(): failed request")) + } + if resp.StatusCode != 200 { + bodyBytes, _ := ioutil.ReadAll(resp.Body) + panic(errors.Errorf("main(): Received non 200 response code: "+ + "Status Code: %v Body: %v", resp.StatusCode, string(bodyBytes))) + } + + var decodedResponse TResponse + + // Process Response. + err = json.NewDecoder(resp.Body).Decode(&decodedResponse) + if err != nil { + panic(errors.Wrap(err, "main(): Failed to decode response\n")) + } + err = resp.Body.Close() + if err != nil { + panic(errors.Wrap(err, "main(): Failed to decode body\n")) + } + + return decodedResponse +} + +func signAndSubmitTxn(txn *lib.MsgDeSoTxn, privKey *btcec.PrivateKey, nodeURL string) { + signature, err := txn.Sign(privKey) + if err != nil { + panic(err) + } + + txn.Signature.SetSignature(signature) + + txnBytes, err := txn.ToBytes(false) + if err != nil { + panic(err) + } + + txnHex := hex.EncodeToString(txnBytes) + + submitTransactionRequest := routes.SubmitTransactionRequest{ + TransactionHex: txnHex, + } + + makePostRequest[routes.SubmitTransactionRequest, routes.SubmitTransactionResponse]( + nodeURL+routes.RoutePathSubmitTransaction, submitTransactionRequest, + ) +} + +func constructSendDESOTxn(senderPubKey *lib.PublicKey, recipientPubKey *lib.PublicKey) routes.SendDeSoResponse { + senderPublicKeyString := lib.PkToString(senderPubKey.ToBytes(), params) + recipientPublicKeyString := lib.PkToString(recipientPubKey.ToBytes(), params) + + sendDESOTxnRequest := routes.SendDeSoRequest{ + SenderPublicKeyBase58Check: senderPublicKeyString, + RecipientPublicKeyOrUsername: recipientPublicKeyString, + AmountNanos: 11 * 1e9, + MinFeeRateNanosPerKB: 1000, + } + + return makePostRequest[routes.SendDeSoRequest, routes.SendDeSoResponse]( + nodeApiUrl+routes.RoutePathSendDeSo, sendDESOTxnRequest, + ) +} + +func constructRegisterAsValidatorTxn(keystore *lib.BLSKeystore, pubKey *lib.PublicKey) routes.ValidatorTxnResponse { + _, votingAuthorization := getBLSVotingAuthorizationAndPublicKey(keystore, pubKey) + + publicKeyString := lib.PkToString(pubKey.ToBytes(), params) + + request := routes.RegisterAsValidatorRequest{ + TransactorPublicKeyBase58Check: publicKeyString, + Domains: []string{validatorDomain}, + DisableDelegatedStake: false, + VotingPublicKey: keystore.GetSigner().GetPublicKey().ToString(), + VotingAuthorization: votingAuthorization.ToString(), + ExtraData: map[string]string{}, + MinFeeRateNanosPerKB: 1000, + TransactionFees: []routes.TransactionFee{}, + } + + return makePostRequest[routes.RegisterAsValidatorRequest, routes.ValidatorTxnResponse]( + nodeApiUrl+routes.RoutePathValidators+"/register", request, + ) +} + +func constructStakeTxn(pubKey *lib.PublicKey) routes.StakeTxnResponse { + publicKeyString := lib.PkToString(pubKey.ToBytes(), params) + + request := routes.StakeRequest{ + TransactorPublicKeyBase58Check: publicKeyString, + ValidatorPublicKeyBase58Check: publicKeyString, + RewardMethod: routes.PayToBalance, + StakeAmountNanos: uint256.NewInt().SetUint64(9 * 1e9), + ExtraData: map[string]string{}, + MinFeeRateNanosPerKB: 1000, + TransactionFees: []routes.TransactionFee{}, + } + + return makePostRequest[routes.StakeRequest, routes.StakeTxnResponse](nodeApiUrl+routes.RoutePathStake, request) +} + +func generatePubAndPrivKeys(seedPhrase string) (*lib.PublicKey, *btcec.PrivateKey) { + seedBytes, err := bip39.NewSeedWithErrorChecking(seedPhrase, "") + if err != nil { + panic(errors.Wrap(err, "main(): Could not generate key pair from mnemonic")) + } + + pubKey, privKey, _, err := lib.ComputeKeysFromSeed(seedBytes, 0, &lib.DeSoTestnetParams) + if err != nil { + panic(errors.Wrap(err, "main(): Could not generate key pair from mnemonic")) + } + + publicKey := lib.NewPublicKey(pubKey.SerializeCompressed()) + return publicKey, privKey +} + +func generateKeystore(seedPhrase string) *lib.BLSKeystore { + keystore, err := lib.NewBLSKeystore(seedPhrase) + if err != nil { + panic(errors.Wrap(err, "main(): Could not generate keystore")) + } + return keystore +} + +func main() { + fmt.Printf("Network Type: %s\n", params.NetworkType.String()) + + desoSourcePubKey, desoSourcePrivKey := generatePubAndPrivKeys(desoSourceSeedPhrase) + + validatorKeystore := generateKeystore(validatorSeedPhrase) + validatorPubKey, validatorPrivKey := generatePubAndPrivKeys(validatorSeedPhrase) + + // First send some DESO to the validator + sendDESOTxn := constructSendDESOTxn(desoSourcePubKey, validatorPubKey) + signAndSubmitTxn(sendDESOTxn.Transaction, desoSourcePrivKey, nodeApiUrl) + fmt.Println("DESO Sent ") + + time.Sleep(5 * time.Second) + + // Register the validator + validatorRegistrationTxn := constructRegisterAsValidatorTxn(validatorKeystore, validatorPubKey) + signAndSubmitTxn(validatorRegistrationTxn.Transaction, validatorPrivKey, nodeApiUrl) + fmt.Println("Validator Registered") + + time.Sleep(5 * time.Second) + + // Have the validator stake to itself + stakeTxn := constructStakeTxn(validatorPubKey) + signAndSubmitTxn(stakeTxn.Transaction, validatorPrivKey, nodeApiUrl) + fmt.Println("Stake Transaction Submitted") +}