mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-06-07 14:46:44 +00:00
[NOD-816] Remove addsubnetwork. (#654)
This commit is contained in:
parent
5a99e4d2f3
commit
4dfc8cf5b0
@ -1,88 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/blockdag"
|
||||
"github.com/kaspanet/kaspad/rpcclient"
|
||||
"github.com/kaspanet/kaspad/rpcmodel"
|
||||
"github.com/kaspanet/kaspad/util/subnetworkid"
|
||||
"github.com/pkg/errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
getSubnetworkRetryDelay = 5 * time.Second
|
||||
maxGetSubnetworkRetries = 12
|
||||
)
|
||||
|
||||
func main() {
|
||||
cfg, err := parseConfig()
|
||||
if err != nil {
|
||||
panic(errors.Errorf("error parsing command-line arguments: %s", err))
|
||||
}
|
||||
|
||||
privateKey, addrPubKeyHash, err := decodeKeys(cfg)
|
||||
if err != nil {
|
||||
panic(errors.Errorf("error decoding public key: %s", err))
|
||||
}
|
||||
|
||||
client, err := connect(cfg)
|
||||
if err != nil {
|
||||
panic(errors.Errorf("could not connect to RPC server: %s", err))
|
||||
}
|
||||
log.Infof("Connected to server %s", cfg.RPCServer)
|
||||
|
||||
fundingOutpoint, fundingTx, err := findUnspentTXO(cfg, client, addrPubKeyHash)
|
||||
if err != nil {
|
||||
panic(errors.Errorf("error finding unspent transactions: %s", err))
|
||||
}
|
||||
if fundingOutpoint == nil || fundingTx == nil {
|
||||
panic(errors.Errorf("could not find any unspent transactions this for key"))
|
||||
}
|
||||
log.Infof("Found transaction to spend: %s:%d", fundingOutpoint.TxID, fundingOutpoint.Index)
|
||||
|
||||
registryTx, err := buildSubnetworkRegistryTx(cfg, fundingOutpoint, fundingTx, privateKey)
|
||||
if err != nil {
|
||||
panic(errors.Errorf("error building subnetwork registry tx: %s", err))
|
||||
}
|
||||
|
||||
_, err = client.SendRawTransaction(registryTx, true)
|
||||
if err != nil {
|
||||
panic(errors.Errorf("failed sending subnetwork registry tx: %s", err))
|
||||
}
|
||||
log.Infof("Successfully sent subnetwork registry transaction")
|
||||
|
||||
subnetworkID, err := blockdag.TxToSubnetworkID(registryTx)
|
||||
if err != nil {
|
||||
panic(errors.Errorf("could not build subnetwork ID: %s", err))
|
||||
}
|
||||
|
||||
err = waitForSubnetworkToBecomeAccepted(client, subnetworkID)
|
||||
if err != nil {
|
||||
panic(errors.Errorf("error waiting for subnetwork to become accepted: %s", err))
|
||||
}
|
||||
log.Infof("Subnetwork '%s' was successfully registered.", subnetworkID)
|
||||
}
|
||||
|
||||
func waitForSubnetworkToBecomeAccepted(client *rpcclient.Client, subnetworkID *subnetworkid.SubnetworkID) error {
|
||||
retries := 0
|
||||
for {
|
||||
_, err := client.GetSubnetwork(subnetworkID.String())
|
||||
if err != nil {
|
||||
var rpcError *rpcmodel.RPCError
|
||||
if ok := errors.As(err, &rpcError); ok && rpcError.Code == rpcmodel.ErrRPCSubnetworkNotFound {
|
||||
log.Infof("Subnetwork not found")
|
||||
|
||||
retries++
|
||||
if retries == maxGetSubnetworkRetries {
|
||||
return errors.Errorf("failed to get subnetwork %d times: %s", maxGetSubnetworkRetries, err)
|
||||
}
|
||||
|
||||
log.Infof("Waiting %d seconds...", int(getSubnetworkRetryDelay.Seconds()))
|
||||
<-time.After(getSubnetworkRetryDelay)
|
||||
continue
|
||||
}
|
||||
return errors.Errorf("failed getting subnetwork: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/jessevdk/go-flags"
|
||||
"github.com/kaspanet/kaspad/config"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var activeConfig *ConfigFlags
|
||||
|
||||
// ActiveConfig returns the active configuration struct
|
||||
func ActiveConfig() *ConfigFlags {
|
||||
return activeConfig
|
||||
}
|
||||
|
||||
// ConfigFlags holds the configurations set by the command line argument
|
||||
type ConfigFlags struct {
|
||||
PrivateKey string `short:"k" long:"private-key" description:"Private key" required:"true"`
|
||||
RPCUser string `short:"u" long:"rpcuser" description:"RPC username" required:"true"`
|
||||
RPCPassword string `short:"P" long:"rpcpass" default-mask:"-" description:"RPC password" required:"true"`
|
||||
RPCServer string `short:"s" long:"rpcserver" description:"RPC server to connect to" required:"true"`
|
||||
RPCCert string `short:"c" long:"rpccert" description:"RPC server certificate chain for validation"`
|
||||
DisableTLS bool `long:"notls" description:"Disable TLS"`
|
||||
GasLimit uint64 `long:"gaslimit" description:"The gas limit of the new subnetwork"`
|
||||
RegistryTxFee uint64 `long:"regtxfee" description:"The fee for the subnetwork registry transaction"`
|
||||
config.NetworkFlags
|
||||
}
|
||||
|
||||
const (
|
||||
defaultSubnetworkGasLimit = 1000
|
||||
defaultRegistryTxFee = 3000
|
||||
)
|
||||
|
||||
func parseConfig() (*ConfigFlags, error) {
|
||||
activeConfig = &ConfigFlags{}
|
||||
parser := flags.NewParser(activeConfig, flags.PrintErrors|flags.HelpFlag)
|
||||
_, err := parser.Parse()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if activeConfig.RPCCert == "" && !activeConfig.DisableTLS {
|
||||
return nil, errors.New("--notls has to be disabled if --cert is used")
|
||||
}
|
||||
|
||||
if activeConfig.RPCCert != "" && activeConfig.DisableTLS {
|
||||
return nil, errors.New("--cert should be omitted if --notls is used")
|
||||
}
|
||||
|
||||
err = activeConfig.ResolveNetwork(parser)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if activeConfig.GasLimit == 0 {
|
||||
activeConfig.GasLimit = defaultSubnetworkGasLimit
|
||||
}
|
||||
|
||||
if activeConfig.RegistryTxFee == 0 {
|
||||
activeConfig.RegistryTxFee = defaultRegistryTxFee
|
||||
}
|
||||
|
||||
return activeConfig, nil
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/rpcclient"
|
||||
"github.com/pkg/errors"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
func connect(cfg *ConfigFlags) (*rpcclient.Client, error) {
|
||||
var cert []byte
|
||||
if !cfg.DisableTLS {
|
||||
var err error
|
||||
cert, err = ioutil.ReadFile(cfg.RPCCert)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("error reading certificates file: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
connCfg := &rpcclient.ConnConfig{
|
||||
Host: cfg.RPCServer,
|
||||
Endpoint: "ws",
|
||||
User: cfg.RPCUser,
|
||||
Pass: cfg.RPCPassword,
|
||||
DisableTLS: cfg.DisableTLS,
|
||||
}
|
||||
|
||||
if !cfg.DisableTLS {
|
||||
connCfg.Certificates = cert
|
||||
}
|
||||
|
||||
client, err := rpcclient.New(connCfg, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("error connecting to address %s: %s", cfg.RPCServer, err)
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/ecc"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/util/base58"
|
||||
)
|
||||
|
||||
func decodeKeys(cfg *ConfigFlags) (*ecc.PrivateKey, *util.AddressPubKeyHash, error) {
|
||||
privateKeyBytes := base58.Decode(cfg.PrivateKey)
|
||||
privateKey, _ := ecc.PrivKeyFromBytes(ecc.S256(), privateKeyBytes)
|
||||
serializedPrivateKey := privateKey.PubKey().SerializeCompressed()
|
||||
|
||||
addr, err := util.NewAddressPubKeyHashFromPublicKey(serializedPrivateKey, ActiveConfig().NetParams().Prefix)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return privateKey, addr, nil
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/logs"
|
||||
)
|
||||
|
||||
var (
|
||||
backendLog = logs.NewBackend()
|
||||
log = backendLog.Logger("ASUB")
|
||||
)
|
@ -1,29 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/kaspanet/kaspad/ecc"
|
||||
"github.com/kaspanet/kaspad/txscript"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func buildSubnetworkRegistryTx(cfg *ConfigFlags, fundingOutpoint *wire.Outpoint, fundingTx *wire.MsgTx, privateKey *ecc.PrivateKey) (*wire.MsgTx, error) {
|
||||
txIn := &wire.TxIn{
|
||||
PreviousOutpoint: *fundingOutpoint,
|
||||
Sequence: wire.MaxTxInSequenceNum,
|
||||
}
|
||||
txOut := &wire.TxOut{
|
||||
ScriptPubKey: fundingTx.TxOut[fundingOutpoint.Index].ScriptPubKey,
|
||||
Value: fundingTx.TxOut[fundingOutpoint.Index].Value - cfg.RegistryTxFee,
|
||||
}
|
||||
registryTx := wire.NewRegistryMsgTx(1, []*wire.TxIn{txIn}, []*wire.TxOut{txOut}, cfg.GasLimit)
|
||||
|
||||
SignatureScript, err := txscript.SignatureScript(registryTx, 0, fundingTx.TxOut[fundingOutpoint.Index].ScriptPubKey,
|
||||
txscript.SigHashAll, privateKey, true)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("failed to build signature script: %s", err)
|
||||
}
|
||||
txIn.SignatureScript = SignatureScript
|
||||
|
||||
return registryTx, nil
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"github.com/kaspanet/kaspad/rpcclient"
|
||||
"github.com/kaspanet/kaspad/rpcmodel"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/kaspanet/kaspad/wire"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
resultsCount = 1000
|
||||
minConfirmations = 10
|
||||
)
|
||||
|
||||
func findUnspentTXO(cfg *ConfigFlags, client *rpcclient.Client, addrPubKeyHash *util.AddressPubKeyHash) (*wire.Outpoint, *wire.MsgTx, error) {
|
||||
txs, err := collectTransactions(client, addrPubKeyHash)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
utxos := buildUTXOs(txs)
|
||||
for outpoint, tx := range utxos {
|
||||
// Skip TXOs that can't pay for registration
|
||||
if tx.TxOut[outpoint.Index].Value < cfg.RegistryTxFee {
|
||||
continue
|
||||
}
|
||||
|
||||
return &outpoint, tx, nil
|
||||
}
|
||||
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
func collectTransactions(client *rpcclient.Client, addrPubKeyHash *util.AddressPubKeyHash) ([]*wire.MsgTx, error) {
|
||||
txs := make([]*wire.MsgTx, 0)
|
||||
skip := 0
|
||||
for {
|
||||
results, err := client.SearchRawTransactionsVerbose(addrPubKeyHash, skip, resultsCount, true, false, nil)
|
||||
if err != nil {
|
||||
// Break when there are no further txs
|
||||
var rpcError *rpcmodel.RPCError
|
||||
if ok := errors.As(err, &rpcError); ok && rpcError.Code == rpcmodel.ErrRPCNoTxInfo {
|
||||
break
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, result := range results {
|
||||
// Mempool transactions bring about unnecessary complexity, so
|
||||
// simply don't bother processing them
|
||||
if result.IsInMempool {
|
||||
continue
|
||||
}
|
||||
|
||||
tx, err := parseRawTransactionResult(result)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("failed to process SearchRawTransactionResult: %s", err)
|
||||
}
|
||||
if tx == nil {
|
||||
continue
|
||||
}
|
||||
if !isTxMatured(tx, *result.Confirmations) {
|
||||
continue
|
||||
}
|
||||
|
||||
txs = append(txs, tx)
|
||||
}
|
||||
|
||||
skip += resultsCount
|
||||
}
|
||||
return txs, nil
|
||||
}
|
||||
|
||||
func parseRawTransactionResult(result *rpcmodel.SearchRawTransactionsResult) (*wire.MsgTx, error) {
|
||||
txBytes, err := hex.DecodeString(result.Hex)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("failed to decode transaction bytes: %s", err)
|
||||
}
|
||||
var tx wire.MsgTx
|
||||
reader := bytes.NewReader(txBytes)
|
||||
err = tx.Deserialize(reader)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("failed to deserialize transaction: %s", err)
|
||||
}
|
||||
return &tx, nil
|
||||
}
|
||||
|
||||
func isTxMatured(tx *wire.MsgTx, confirmations uint64) bool {
|
||||
if !tx.IsCoinBase() {
|
||||
return confirmations >= minConfirmations
|
||||
}
|
||||
return confirmations >= ActiveConfig().NetParams().BlockCoinbaseMaturity
|
||||
}
|
||||
|
||||
func buildUTXOs(txs []*wire.MsgTx) map[wire.Outpoint]*wire.MsgTx {
|
||||
utxos := make(map[wire.Outpoint]*wire.MsgTx)
|
||||
for _, tx := range txs {
|
||||
for i := range tx.TxOut {
|
||||
outpoint := wire.NewOutpoint(tx.TxID(), uint32(i))
|
||||
utxos[*outpoint] = tx
|
||||
}
|
||||
}
|
||||
for _, tx := range txs {
|
||||
for _, input := range tx.TxIn {
|
||||
delete(utxos, input.PreviousOutpoint)
|
||||
}
|
||||
}
|
||||
return utxos
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user