github.com/0chain/gosdk@v1.17.11/zcncore/transaction.go (about)

     1  //go:build !mobile
     2  // +build !mobile
     3  
     4  package zcncore
     5  
     6  import (
     7  	"context"
     8  	"encoding/json"
     9  	"fmt"
    10  	"math"
    11  	"net/http"
    12  	"sync"
    13  	"time"
    14  
    15  	"github.com/0chain/errors"
    16  	"github.com/0chain/gosdk/core/block"
    17  	"github.com/0chain/gosdk/core/common"
    18  	"github.com/0chain/gosdk/core/encryption"
    19  	"github.com/0chain/gosdk/core/node"
    20  	"github.com/0chain/gosdk/core/transaction"
    21  	"github.com/0chain/gosdk/core/util"
    22  	"github.com/0chain/gosdk/core/zcncrypto"
    23  )
    24  
    25  // Provider represents the type of provider.
    26  type Provider int
    27  
    28  const (
    29  	ProviderMiner Provider = iota + 1
    30  	ProviderSharder
    31  	ProviderBlobber
    32  	ProviderValidator
    33  	ProviderAuthorizer
    34  )
    35  
    36  type TransactionVelocity = float64
    37  
    38  // Transaction velocity vs cost factor
    39  // TODO: Pass it to miner to calculate real time factor
    40  const (
    41  	RegularTransaction TransactionVelocity = 1.0
    42  	FastTransaction    TransactionVelocity = 1.3
    43  	FasterTransaction  TransactionVelocity = 1.6
    44  )
    45  
    46  type ConfirmationStatus int
    47  
    48  const (
    49  	Undefined ConfirmationStatus = iota
    50  	Success
    51  
    52  	// ChargeableError is an error that still charges the user for the transaction.
    53  	ChargeableError
    54  )
    55  
    56  type Miner struct {
    57  	ID         string      `json:"id"`
    58  	N2NHost    string      `json:"n2n_host"`
    59  	Host       string      `json:"host"`
    60  	Port       int         `json:"port"`
    61  	PublicKey  string      `json:"public_key"`
    62  	ShortName  string      `json:"short_name"`
    63  	BuildTag   string      `json:"build_tag"`
    64  	TotalStake int64       `json:"total_stake"`
    65  	Stat       interface{} `json:"stat"`
    66  }
    67  
    68  // Node represents a node (miner or sharder) in the network.
    69  type Node struct {
    70  	Miner     Miner `json:"simple_miner"`
    71  	StakePool `json:"stake_pool"`
    72  }
    73  
    74  // MinerSCNodes list of nodes registered to the miner smart contract
    75  type MinerSCNodes struct {
    76  	Nodes []Node `json:"Nodes"`
    77  }
    78  
    79  type VestingSCConfig struct {
    80  	MinLock              common.Balance `json:"min_lock"`
    81  	MinDuration          time.Duration  `json:"min_duration"`
    82  	MaxDuration          time.Duration  `json:"max_duration"`
    83  	MaxDestinations      int            `json:"max_destinations"`
    84  	MaxDescriptionLength int            `json:"max_description_length"`
    85  }
    86  
    87  type DelegatePool struct {
    88  	Balance      int64  `json:"balance"`
    89  	Reward       int64  `json:"reward"`
    90  	Status       int    `json:"status"`
    91  	RoundCreated int64  `json:"round_created"` // used for cool down
    92  	DelegateID   string `json:"delegate_id"`
    93  }
    94  
    95  type StakePool struct {
    96  	Pools    map[string]*DelegatePool `json:"pools"`
    97  	Reward   int64                    `json:"rewards"`
    98  	Settings StakePoolSettings        `json:"settings"`
    99  	Minter   int                      `json:"minter"`
   100  }
   101  
   102  type stakePoolRequest struct {
   103  	ProviderType Provider `json:"provider_type,omitempty"`
   104  	ProviderID   string   `json:"provider_id,omitempty"`
   105  }
   106  
   107  type MinerSCDelegatePoolInfo struct {
   108  	ID         common.Key     `json:"id"`
   109  	Balance    common.Balance `json:"balance"`
   110  	Reward     common.Balance `json:"reward"`      // uncollected reread
   111  	RewardPaid common.Balance `json:"reward_paid"` // total reward all time
   112  	Status     string         `json:"status"`
   113  }
   114  
   115  // MinerSCUserPoolsInfo represents the user stake pools information
   116  type MinerSCUserPoolsInfo struct {
   117  	Pools map[string][]*MinerSCDelegatePoolInfo `json:"pools"`
   118  }
   119  
   120  type TransactionCommon interface {
   121  	// ExecuteSmartContract implements wrapper for smart contract function
   122  	ExecuteSmartContract(address, methodName string, input interface{}, val uint64, feeOpts ...FeeOption) (*transaction.Transaction, error)
   123  	// Send implements sending token to a given clientid
   124  	Send(toClientID string, val uint64, desc string) error
   125  
   126  	//RegisterMultiSig registers a group wallet and subwallets with MultisigSC
   127  	RegisterMultiSig(walletstr, mswallet string) error
   128  
   129  	VestingAdd(ar *VestingAddRequest, value uint64) error
   130  
   131  	MinerSCLock(providerId string, providerType Provider, lock uint64) error
   132  	MinerSCUnlock(providerId string, providerType Provider) error
   133  	MinerSCCollectReward(providerID string, providerType Provider) error
   134  	MinerSCKill(providerID string, providerType Provider) error
   135  
   136  	StorageSCCollectReward(providerID string, providerType Provider) error
   137  
   138  	FinalizeAllocation(allocID string) error
   139  	CancelAllocation(allocID string) error
   140  	CreateAllocation(car *CreateAllocationRequest, lock uint64) error //
   141  	CreateReadPool() error
   142  	ReadPoolLock(allocID string, blobberID string, duration int64, lock uint64) error
   143  	ReadPoolUnlock() error
   144  	StakePoolLock(providerId string, providerType Provider, lock uint64) error
   145  	StakePoolUnlock(providerId string, providerType Provider) error
   146  	UpdateBlobberSettings(blobber *Blobber) error
   147  	UpdateValidatorSettings(validator *Validator) error
   148  	UpdateAllocation(allocID string, sizeDiff int64, expirationDiff int64, lock uint64) error
   149  	WritePoolLock(allocID string, blobberID string, duration int64, lock uint64) error
   150  	WritePoolUnlock(allocID string) error
   151  
   152  	VestingUpdateConfig(*InputMap) error
   153  	MinerScUpdateConfig(*InputMap) error
   154  	MinerScUpdateGlobals(*InputMap) error
   155  	StorageScUpdateConfig(*InputMap) error
   156  	AddHardfork(ip *InputMap) (err error)
   157  	FaucetUpdateConfig(*InputMap) error
   158  	ZCNSCUpdateGlobalConfig(*InputMap) error
   159  
   160  	MinerSCMinerSettings(*MinerSCMinerInfo) error
   161  	MinerSCSharderSettings(*MinerSCMinerInfo) error
   162  	MinerSCDeleteMiner(*MinerSCMinerInfo) error
   163  	MinerSCDeleteSharder(*MinerSCMinerInfo) error
   164  
   165  	// ZCNSCUpdateAuthorizerConfig updates authorizer config by ID
   166  	ZCNSCUpdateAuthorizerConfig(*AuthorizerNode) error
   167  	// ZCNSCAddAuthorizer adds authorizer
   168  	ZCNSCAddAuthorizer(*AddAuthorizerPayload) error
   169  
   170  	// ZCNSCAuthorizerHealthCheck provides health check for authorizer
   171  	ZCNSCAuthorizerHealthCheck(*AuthorizerHealthCheckPayload) error
   172  
   173  	// GetVerifyConfirmationStatus implements the verification status from sharders
   174  	GetVerifyConfirmationStatus() ConfirmationStatus
   175  
   176  	// ZCNSCDeleteAuthorizer deletes authorizer
   177  	ZCNSCDeleteAuthorizer(*DeleteAuthorizerPayload) error
   178  
   179  	ZCNSCCollectReward(providerID string, providerType Provider) error
   180  }
   181  
   182  // compiler time check
   183  var (
   184  	_ TransactionScheme = (*Transaction)(nil)
   185  	_ TransactionScheme = (*TransactionWithAuth)(nil)
   186  )
   187  
   188  // TransactionScheme implements few methods for block chain.
   189  //
   190  // Note: to be buildable on MacOSX all arguments should have names.
   191  type TransactionScheme interface {
   192  	TransactionCommon
   193  	// SetTransactionCallback implements storing the callback
   194  	// used to call after the transaction or verification is completed
   195  	SetTransactionCallback(cb TransactionCallback) error
   196  	// StoreData implements store the data to blockchain
   197  	StoreData(data string) error
   198  	// ExecuteFaucetSCWallet implements the `Faucet Smart contract` for a given wallet
   199  	ExecuteFaucetSCWallet(walletStr string, methodName string, input []byte) error
   200  	// GetTransactionHash implements retrieval of hash of the submitted transaction
   201  	GetTransactionHash() string
   202  	// SetTransactionHash implements verify a previous transaction status
   203  	SetTransactionHash(hash string) error
   204  	// SetTransactionNonce implements method to set the transaction nonce
   205  	SetTransactionNonce(txnNonce int64) error
   206  	// Verify implements verify the transaction
   207  	Verify() error
   208  	// GetVerifyOutput implements the verification output from sharders
   209  	GetVerifyOutput() string
   210  	// GetTransactionError implements error string in case of transaction failure
   211  	GetTransactionError() string
   212  	// GetVerifyError implements error string in case of verify failure error
   213  	GetVerifyError() string
   214  	// GetTransactionNonce returns nonce
   215  	GetTransactionNonce() int64
   216  
   217  	// Output of transaction.
   218  	Output() []byte
   219  
   220  	// Hash Transaction status regardless of status
   221  	Hash() string
   222  
   223  	// Vesting SC
   224  
   225  	VestingTrigger(poolID string) error
   226  	VestingStop(sr *VestingStopRequest) error
   227  	VestingUnlock(poolID string) error
   228  	VestingDelete(poolID string) error
   229  
   230  	// Miner SC
   231  }
   232  
   233  // PriceRange represents a price range allowed by user to filter blobbers.
   234  type PriceRange struct {
   235  	Min common.Balance `json:"min"`
   236  	Max common.Balance `json:"max"`
   237  }
   238  
   239  // CreateAllocationRequest is information to create allocation.
   240  type CreateAllocationRequest struct {
   241  	DataShards      int              `json:"data_shards"`
   242  	ParityShards    int              `json:"parity_shards"`
   243  	Size            common.Size      `json:"size"`
   244  	Expiration      common.Timestamp `json:"expiration_date"`
   245  	Owner           string           `json:"owner_id"`
   246  	OwnerPublicKey  string           `json:"owner_public_key"`
   247  	Blobbers        []string         `json:"blobbers"`
   248  	ReadPriceRange  PriceRange       `json:"read_price_range"`
   249  	WritePriceRange PriceRange       `json:"write_price_range"`
   250  }
   251  
   252  type StakePoolSettings struct {
   253  	DelegateWallet *string  `json:"delegate_wallet,omitempty"`
   254  	NumDelegates   *int     `json:"num_delegates,omitempty"`
   255  	ServiceCharge  *float64 `json:"service_charge,omitempty"`
   256  }
   257  
   258  type Terms struct {
   259  	ReadPrice        common.Balance `json:"read_price"`  // tokens / GB
   260  	WritePrice       common.Balance `json:"write_price"` // tokens / GB `
   261  	MaxOfferDuration time.Duration  `json:"max_offer_duration"`
   262  }
   263  
   264  // Blobber represents a blobber node.
   265  type Blobber struct {
   266  	// ID is the blobber ID.
   267  	ID common.Key `json:"id"`
   268  	// BaseURL is the blobber's base URL used to access the blobber
   269  	BaseURL string `json:"url"`
   270  	// Terms of storage service of the blobber (read/write price, max offer duration)
   271  	Terms Terms `json:"terms"`
   272  	// Capacity is the total capacity of the blobber
   273  	Capacity common.Size `json:"capacity"`
   274  	// Used is the capacity of the blobber used to create allocations
   275  	Allocated common.Size `json:"allocated"`
   276  	// LastHealthCheck is the last time the blobber was checked for health
   277  	LastHealthCheck common.Timestamp `json:"last_health_check"`
   278  	// StakePoolSettings is the settings of the blobber's stake pool
   279  	StakePoolSettings StakePoolSettings `json:"stake_pool_settings"`
   280  	// NotAvailable is true if the blobber is not available
   281  	NotAvailable bool `json:"not_available"`
   282  	// IsRestricted is true if the blobber is restricted.
   283  	// Restricted blobbers needs to be authenticated using AuthTickets in order to be used for allocation creation.
   284  	// Check Restricted Blobbers documentation for more details.
   285  	IsRestricted bool `json:"is_restricted"`
   286  }
   287  
   288  type Validator struct {
   289  	ID                common.Key        `json:"id"`
   290  	BaseURL           string            `json:"url"`
   291  	StakePoolSettings StakePoolSettings `json:"stake_pool_settings"`
   292  }
   293  
   294  // AddAuthorizerPayload represents the payload for adding an authorizer.
   295  type AddAuthorizerPayload struct {
   296  	PublicKey         string                      `json:"public_key"`
   297  	URL               string                      `json:"url"`
   298  	StakePoolSettings AuthorizerStakePoolSettings `json:"stake_pool_settings"` // Used to initially create stake pool
   299  }
   300  
   301  // DeleteAuthorizerPayload represents the payload for deleting an authorizer.
   302  type DeleteAuthorizerPayload struct {
   303  	ID string `json:"id"` // authorizer ID
   304  }
   305  
   306  // AuthorizerHealthCheckPayload represents the payload for authorizer health check.
   307  type AuthorizerHealthCheckPayload struct {
   308  	ID string `json:"id"` // authorizer ID
   309  }
   310  
   311  // AuthorizerStakePoolSettings represents the settings for an authorizer's stake pool.
   312  type AuthorizerStakePoolSettings struct {
   313  	DelegateWallet string  `json:"delegate_wallet"`
   314  	NumDelegates   int     `json:"num_delegates"`
   315  	ServiceCharge  float64 `json:"service_charge"`
   316  }
   317  
   318  type AuthorizerConfig struct {
   319  	Fee common.Balance `json:"fee"`
   320  }
   321  
   322  // InputMap represents a map of input fields.
   323  type InputMap struct {
   324  	Fields map[string]string `json:"Fields"`
   325  }
   326  
   327  func newTransaction(cb TransactionCallback, txnFee uint64, nonce int64) (*Transaction, error) {
   328  	t := &Transaction{}
   329  	t.txn = transaction.NewTransactionEntity(_config.wallet.ClientID, _config.chain.ChainID, _config.wallet.ClientKey, nonce)
   330  	t.txnStatus, t.verifyStatus = StatusUnknown, StatusUnknown
   331  	t.txnCb = cb
   332  	t.txn.TransactionNonce = nonce
   333  	t.txn.TransactionFee = txnFee
   334  	return t, nil
   335  }
   336  
   337  // NewTransaction new generic transaction object for any operation
   338  //   - cb: callback for transaction state
   339  //   - txnFee: Transaction fees (in SAS tokens)
   340  //   - nonce: latest nonce of current wallet. please set it with 0 if you don't know the latest value
   341  func NewTransaction(cb TransactionCallback, txnFee uint64, nonce int64) (TransactionScheme, error) {
   342  	err := CheckConfig()
   343  	if err != nil {
   344  		return nil, err
   345  	}
   346  	if _config.isSplitWallet {
   347  		logging.Info("New transaction interface with auth")
   348  		return newTransactionWithAuth(cb, txnFee, nonce)
   349  	}
   350  
   351  	logging.Info("New transaction interface")
   352  	return newTransaction(cb, txnFee, nonce)
   353  }
   354  
   355  func (t *Transaction) createSmartContractTxn(address, methodName string, input interface{}, value uint64, opts ...FeeOption) error {
   356  	sn := transaction.SmartContractTxnData{Name: methodName, InputArgs: input}
   357  	snBytes, err := json.Marshal(sn)
   358  	if err != nil {
   359  		return errors.Wrap(err, "create smart contract failed due to invalid data")
   360  	}
   361  
   362  	t.txn.TransactionType = transaction.TxnTypeSmartContract
   363  	t.txn.ToClientID = address
   364  	t.txn.TransactionData = string(snBytes)
   365  	t.txn.Value = value
   366  
   367  	if t.txn.TransactionFee > 0 {
   368  		return nil
   369  	}
   370  
   371  	tf := &TxnFeeOption{}
   372  	for _, opt := range opts {
   373  		opt(tf)
   374  	}
   375  
   376  	if tf.noEstimateFee {
   377  		return nil
   378  	}
   379  
   380  	// TODO: check if transaction is exempt to avoid unnecessary fee estimation
   381  	minFee, err := transaction.EstimateFee(t.txn, _config.chain.Miners, 0.2)
   382  	if err != nil {
   383  		return err
   384  	}
   385  
   386  	t.txn.TransactionFee = minFee
   387  
   388  	return nil
   389  }
   390  
   391  func (t *Transaction) createFaucetSCWallet(walletStr string, methodName string, input []byte) (*zcncrypto.Wallet, error) {
   392  	w, err := getWallet(walletStr)
   393  	if err != nil {
   394  		fmt.Printf("Error while parsing the wallet. %v\n", err)
   395  		return nil, err
   396  	}
   397  	err = t.createSmartContractTxn(FaucetSmartContractAddress, methodName, input, 0)
   398  	if err != nil {
   399  		return nil, err
   400  	}
   401  	return w, nil
   402  }
   403  
   404  func (t *Transaction) ExecuteSmartContract(address, methodName string, input interface{}, val uint64, opts ...FeeOption) (*transaction.Transaction, error) {
   405  	err := t.createSmartContractTxn(address, methodName, input, val, opts...)
   406  	if err != nil {
   407  		return nil, err
   408  	}
   409  	go func() {
   410  		t.setNonceAndSubmit()
   411  	}()
   412  	return t.txn, nil
   413  }
   414  
   415  func (t *Transaction) Send(toClientID string, val uint64, desc string) error {
   416  	txnData, err := json.Marshal(transaction.SmartContractTxnData{Name: "transfer", InputArgs: SendTxnData{Note: desc}})
   417  	if err != nil {
   418  		return errors.New("", "Could not serialize description to transaction_data")
   419  	}
   420  
   421  	t.txn.TransactionType = transaction.TxnTypeSend
   422  	t.txn.ToClientID = toClientID
   423  	t.txn.Value = val
   424  	t.txn.TransactionData = string(txnData)
   425  	if t.txn.TransactionFee == 0 {
   426  		fee, err := transaction.EstimateFee(t.txn, _config.chain.Miners, 0.2)
   427  		if err != nil {
   428  			return err
   429  		}
   430  		t.txn.TransactionFee = fee
   431  	}
   432  
   433  	go func() {
   434  		t.setNonceAndSubmit()
   435  	}()
   436  	return nil
   437  }
   438  
   439  func (t *Transaction) SendWithSignatureHash(toClientID string, val uint64, desc string, sig string, CreationDate int64, hash string) error {
   440  	txnData, err := json.Marshal(SendTxnData{Note: desc})
   441  	if err != nil {
   442  		return errors.New("", "Could not serialize description to transaction_data")
   443  	}
   444  	t.txn.TransactionType = transaction.TxnTypeSend
   445  	t.txn.ToClientID = toClientID
   446  	t.txn.Value = val
   447  	t.txn.Hash = hash
   448  	t.txn.TransactionData = string(txnData)
   449  	t.txn.Signature = sig
   450  	t.txn.CreationDate = CreationDate
   451  	if t.txn.TransactionFee == 0 {
   452  		fee, err := transaction.EstimateFee(t.txn, _config.chain.Miners, 0.2)
   453  		if err != nil {
   454  			return err
   455  		}
   456  		t.txn.TransactionFee = fee
   457  	}
   458  
   459  	go func() {
   460  		t.setNonceAndSubmit()
   461  	}()
   462  	return nil
   463  }
   464  
   465  type VestingDest struct {
   466  	ID     string         `json:"id"`     // destination ID
   467  	Amount common.Balance `json:"amount"` // amount to vest for the destination
   468  }
   469  
   470  type VestingAddRequest struct {
   471  	Description  string           `json:"description"`  // allow empty
   472  	StartTime    common.Timestamp `json:"start_time"`   //
   473  	Duration     time.Duration    `json:"duration"`     //
   474  	Destinations []*VestingDest   `json:"destinations"` //
   475  }
   476  
   477  func (t *Transaction) VestingAdd(ar *VestingAddRequest, value uint64) (
   478  	err error) {
   479  
   480  	err = t.createSmartContractTxn(VestingSmartContractAddress,
   481  		transaction.VESTING_ADD, ar, value)
   482  	if err != nil {
   483  		logging.Error(err)
   484  		return
   485  	}
   486  	go func() { t.setNonceAndSubmit() }()
   487  	return
   488  }
   489  
   490  func (t *Transaction) VestingStop(sr *VestingStopRequest) (err error) {
   491  	err = t.createSmartContractTxn(VestingSmartContractAddress,
   492  		transaction.VESTING_STOP, sr, 0)
   493  	if err != nil {
   494  		logging.Error(err)
   495  		return
   496  	}
   497  	go func() { t.setNonceAndSubmit() }()
   498  	return
   499  }
   500  
   501  func (t *Transaction) vestingPoolTxn(function string, poolID string,
   502  	value uint64) error {
   503  
   504  	return t.createSmartContractTxn(VestingSmartContractAddress,
   505  		function, vestingRequest{PoolID: common.Key(poolID)}, value)
   506  }
   507  
   508  func (t *Transaction) VestingTrigger(poolID string) (err error) {
   509  
   510  	err = t.vestingPoolTxn(transaction.VESTING_TRIGGER, poolID, 0)
   511  	if err != nil {
   512  		logging.Error(err)
   513  		return
   514  	}
   515  	go func() { t.setNonceAndSubmit() }()
   516  	return
   517  }
   518  
   519  func (t *Transaction) VestingUnlock(poolID string) (err error) {
   520  	err = t.vestingPoolTxn(transaction.VESTING_UNLOCK, poolID, 0)
   521  	if err != nil {
   522  		logging.Error(err)
   523  		return
   524  	}
   525  	go func() { t.setNonceAndSubmit() }()
   526  	return
   527  }
   528  
   529  func (t *Transaction) VestingDelete(poolID string) (err error) {
   530  	err = t.vestingPoolTxn(transaction.VESTING_DELETE, poolID, 0)
   531  	if err != nil {
   532  		logging.Error(err)
   533  		return
   534  	}
   535  	go func() { t.setNonceAndSubmit() }()
   536  	return
   537  }
   538  
   539  func (t *Transaction) MinerSCLock(providerId string, providerType Provider, lock uint64) error {
   540  	if lock > math.MaxInt64 {
   541  		return errors.New("invalid_lock", "int64 overflow on lock value")
   542  	}
   543  
   544  	pr := &stakePoolRequest{
   545  		ProviderID:   providerId,
   546  		ProviderType: providerType,
   547  	}
   548  	err := t.createSmartContractTxn(MinerSmartContractAddress,
   549  		transaction.MINERSC_LOCK, pr, lock)
   550  	if err != nil {
   551  		logging.Error(err)
   552  		return err
   553  	}
   554  	go func() { t.setNonceAndSubmit() }()
   555  	return err
   556  }
   557  func (t *Transaction) MinerSCUnlock(providerId string, providerType Provider) error {
   558  	pr := &stakePoolRequest{
   559  		ProviderID:   providerId,
   560  		ProviderType: providerType,
   561  	}
   562  	err := t.createSmartContractTxn(MinerSmartContractAddress,
   563  		transaction.MINERSC_UNLOCK, pr, 0)
   564  	if err != nil {
   565  		logging.Error(err)
   566  		return err
   567  	}
   568  	go func() { t.setNonceAndSubmit() }()
   569  	return err
   570  }
   571  
   572  func (t *Transaction) MinerSCCollectReward(providerId string, providerType Provider) error {
   573  	pr := &scCollectReward{
   574  		ProviderId:   providerId,
   575  		ProviderType: int(providerType),
   576  	}
   577  	err := t.createSmartContractTxn(MinerSmartContractAddress,
   578  		transaction.MINERSC_COLLECT_REWARD, pr, 0)
   579  	if err != nil {
   580  		logging.Error(err)
   581  		return err
   582  	}
   583  	go func() { t.setNonceAndSubmit() }()
   584  	return err
   585  }
   586  
   587  func (t *Transaction) MinerSCKill(providerId string, providerType Provider) error {
   588  	pr := &scCollectReward{
   589  		ProviderId:   providerId,
   590  		ProviderType: int(providerType),
   591  	}
   592  	var name string
   593  	switch providerType {
   594  	case ProviderMiner:
   595  		name = transaction.MINERSC_KILL_MINER
   596  	case ProviderSharder:
   597  		name = transaction.MINERSC_KILL_SHARDER
   598  	default:
   599  		return fmt.Errorf("kill provider type %v not implimented", providerType)
   600  	}
   601  
   602  	err := t.createSmartContractTxn(MinerSmartContractAddress, name, pr, 0)
   603  	if err != nil {
   604  		logging.Error(err)
   605  		return err
   606  	}
   607  	go func() { t.setNonceAndSubmit() }()
   608  	return err
   609  }
   610  
   611  func (t *Transaction) StorageSCCollectReward(providerId string, providerType Provider) error {
   612  	pr := &scCollectReward{
   613  		ProviderId:   providerId,
   614  		ProviderType: int(providerType),
   615  	}
   616  	err := t.createSmartContractTxn(StorageSmartContractAddress,
   617  		transaction.STORAGESC_COLLECT_REWARD, pr, 0)
   618  	if err != nil {
   619  		logging.Error(err)
   620  		return err
   621  	}
   622  	go t.setNonceAndSubmit()
   623  	return err
   624  }
   625  
   626  // FinalizeAllocation transaction.
   627  func (t *Transaction) FinalizeAllocation(allocID string) (
   628  	err error) {
   629  
   630  	type finiRequest struct {
   631  		AllocationID string `json:"allocation_id"`
   632  	}
   633  	err = t.createSmartContractTxn(StorageSmartContractAddress,
   634  		transaction.STORAGESC_FINALIZE_ALLOCATION, &finiRequest{
   635  			AllocationID: allocID,
   636  		}, 0)
   637  	if err != nil {
   638  		logging.Error(err)
   639  		return
   640  	}
   641  
   642  	go func() { t.setNonceAndSubmit() }()
   643  	return
   644  }
   645  
   646  // CancelAllocation transaction.
   647  func (t *Transaction) CancelAllocation(allocID string) (
   648  	err error) {
   649  
   650  	type cancelRequest struct {
   651  		AllocationID string `json:"allocation_id"`
   652  	}
   653  	err = t.createSmartContractTxn(StorageSmartContractAddress,
   654  		transaction.STORAGESC_CANCEL_ALLOCATION, &cancelRequest{
   655  			AllocationID: allocID,
   656  		}, 0)
   657  	if err != nil {
   658  		logging.Error(err)
   659  		return
   660  	}
   661  	go func() { t.setNonceAndSubmit() }()
   662  	return
   663  }
   664  
   665  // CreateAllocation transaction.
   666  func (t *Transaction) CreateAllocation(car *CreateAllocationRequest,
   667  	lock uint64) (err error) {
   668  	err = t.createSmartContractTxn(StorageSmartContractAddress,
   669  		transaction.STORAGESC_CREATE_ALLOCATION, car, lock)
   670  	if err != nil {
   671  		logging.Error(err)
   672  		return
   673  	}
   674  
   675  	go func() { t.setNonceAndSubmit() }()
   676  	return
   677  }
   678  
   679  // CreateReadPool for current user.
   680  func (t *Transaction) CreateReadPool() (err error) {
   681  	err = t.createSmartContractTxn(StorageSmartContractAddress,
   682  		transaction.STORAGESC_CREATE_READ_POOL, nil, 0)
   683  	if err != nil {
   684  		logging.Error(err)
   685  		return
   686  	}
   687  	go func() { t.setNonceAndSubmit() }()
   688  	return
   689  }
   690  
   691  // ReadPoolLock locks tokens for current user and given allocation, using given
   692  // duration. If blobberID is not empty, then tokens will be locked for given
   693  // allocation->blobber only.
   694  func (t *Transaction) ReadPoolLock(allocID, blobberID string, duration int64, lock uint64) (err error) {
   695  	if lock > math.MaxInt64 {
   696  		return errors.New("invalid_lock", "int64 overflow on lock value")
   697  	}
   698  
   699  	type lockRequest struct {
   700  		Duration     time.Duration `json:"duration"`
   701  		AllocationID string        `json:"allocation_id"`
   702  		BlobberID    string        `json:"blobber_id,omitempty"`
   703  	}
   704  
   705  	var lr lockRequest
   706  	lr.Duration = time.Duration(duration)
   707  	lr.AllocationID = allocID
   708  	lr.BlobberID = blobberID
   709  
   710  	err = t.createSmartContractTxn(StorageSmartContractAddress,
   711  		transaction.STORAGESC_READ_POOL_LOCK, &lr, lock)
   712  	if err != nil {
   713  		logging.Error(err)
   714  		return
   715  	}
   716  	go func() { t.setNonceAndSubmit() }()
   717  	return
   718  }
   719  
   720  // ReadPoolUnlock for current user and given pool.
   721  func (t *Transaction) ReadPoolUnlock() (err error) {
   722  	err = t.createSmartContractTxn(StorageSmartContractAddress,
   723  		transaction.STORAGESC_READ_POOL_UNLOCK, nil, 0)
   724  	if err != nil {
   725  		logging.Error(err)
   726  		return
   727  	}
   728  	go func() { t.setNonceAndSubmit() }()
   729  	return
   730  }
   731  
   732  // StakePoolLock used to lock tokens in a stake pool of a blobber.
   733  func (t *Transaction) StakePoolLock(providerId string, providerType Provider, lock uint64) error {
   734  
   735  	if lock > math.MaxInt64 {
   736  		return errors.New("invalid_lock", "int64 overflow on lock value")
   737  	}
   738  
   739  	type stakePoolRequest struct {
   740  		ProviderType Provider `json:"provider_type,omitempty"`
   741  		ProviderID   string   `json:"provider_id,omitempty"`
   742  	}
   743  
   744  	spr := stakePoolRequest{
   745  		ProviderType: providerType,
   746  		ProviderID:   providerId,
   747  	}
   748  
   749  	err := t.createSmartContractTxn(StorageSmartContractAddress,
   750  		transaction.STORAGESC_STAKE_POOL_LOCK, &spr, lock)
   751  	if err != nil {
   752  		logging.Error(err)
   753  		return err
   754  	}
   755  	go func() { t.setNonceAndSubmit() }()
   756  	return nil
   757  }
   758  
   759  // StakePoolUnlock by blobberID and poolID.
   760  func (t *Transaction) StakePoolUnlock(providerId string, providerType Provider) error {
   761  
   762  	type stakePoolRequest struct {
   763  		ProviderType Provider `json:"provider_type,omitempty"`
   764  		ProviderID   string   `json:"provider_id,omitempty"`
   765  	}
   766  
   767  	spr := stakePoolRequest{
   768  		ProviderType: providerType,
   769  		ProviderID:   providerId,
   770  	}
   771  
   772  	err := t.createSmartContractTxn(StorageSmartContractAddress, transaction.STORAGESC_STAKE_POOL_UNLOCK, &spr, 0)
   773  	if err != nil {
   774  		logging.Error(err)
   775  		return err
   776  	}
   777  	go func() { t.setNonceAndSubmit() }()
   778  	return nil
   779  }
   780  
   781  // UpdateBlobberSettings update settings of a blobber.
   782  func (t *Transaction) UpdateBlobberSettings(b *Blobber) (err error) {
   783  
   784  	err = t.createSmartContractTxn(StorageSmartContractAddress,
   785  		transaction.STORAGESC_UPDATE_BLOBBER_SETTINGS, b, 0)
   786  	if err != nil {
   787  		logging.Error(err)
   788  		return
   789  	}
   790  	go func() { t.setNonceAndSubmit() }()
   791  	return
   792  }
   793  
   794  // UpdateAllocation transaction.
   795  func (t *Transaction) UpdateAllocation(allocID string, sizeDiff int64,
   796  	expirationDiff int64, lock uint64) (err error) {
   797  
   798  	if lock > math.MaxInt64 {
   799  		return errors.New("invalid_lock", "int64 overflow on lock value")
   800  	}
   801  
   802  	type updateAllocationRequest struct {
   803  		ID         string `json:"id"`              // allocation id
   804  		Size       int64  `json:"size"`            // difference
   805  		Expiration int64  `json:"expiration_date"` // difference
   806  	}
   807  
   808  	var uar updateAllocationRequest
   809  	uar.ID = allocID
   810  	uar.Size = sizeDiff
   811  	uar.Expiration = expirationDiff
   812  
   813  	err = t.createSmartContractTxn(StorageSmartContractAddress,
   814  		transaction.STORAGESC_UPDATE_ALLOCATION, &uar, lock)
   815  	if err != nil {
   816  		logging.Error(err)
   817  		return
   818  	}
   819  	go func() { t.setNonceAndSubmit() }()
   820  	return
   821  }
   822  
   823  // WritePoolLock locks tokens for current user and given allocation, using given
   824  // duration. If blobberID is not empty, then tokens will be locked for given
   825  // allocation->blobber only.
   826  func (t *Transaction) WritePoolLock(allocID, blobberID string, duration int64,
   827  	lock uint64) (err error) {
   828  
   829  	if lock > math.MaxInt64 {
   830  		return errors.New("invalid_lock", "int64 overflow on lock value")
   831  	}
   832  
   833  	type lockRequest struct {
   834  		Duration     time.Duration `json:"duration"`
   835  		AllocationID string        `json:"allocation_id"`
   836  		BlobberID    string        `json:"blobber_id,omitempty"`
   837  	}
   838  
   839  	var lr lockRequest
   840  	lr.Duration = time.Duration(duration)
   841  	lr.AllocationID = allocID
   842  	lr.BlobberID = blobberID
   843  
   844  	err = t.createSmartContractTxn(StorageSmartContractAddress,
   845  		transaction.STORAGESC_WRITE_POOL_LOCK, &lr, lock)
   846  	if err != nil {
   847  		logging.Error(err)
   848  		return
   849  	}
   850  	go func() { t.setNonceAndSubmit() }()
   851  	return
   852  }
   853  
   854  // WritePoolUnlock for current user and given pool.
   855  func (t *Transaction) WritePoolUnlock(allocID string) (
   856  	err error) {
   857  
   858  	var ur = struct {
   859  		AllocationID string `json:"allocation_id"`
   860  	}{
   861  		AllocationID: allocID,
   862  	}
   863  
   864  	err = t.createSmartContractTxn(StorageSmartContractAddress,
   865  		transaction.STORAGESC_WRITE_POOL_UNLOCK, &ur, 0)
   866  	if err != nil {
   867  		logging.Error(err)
   868  		return
   869  	}
   870  	go func() { t.setNonceAndSubmit() }()
   871  	return
   872  }
   873  
   874  func (t *Transaction) VestingUpdateConfig(vscc *InputMap) (err error) {
   875  
   876  	err = t.createSmartContractTxn(VestingSmartContractAddress,
   877  		transaction.VESTING_UPDATE_SETTINGS, vscc, 0)
   878  	if err != nil {
   879  		logging.Error(err)
   880  		return
   881  	}
   882  	go func() { t.setNonceAndSubmit() }()
   883  	return
   884  }
   885  
   886  // faucet smart contract
   887  
   888  func (t *Transaction) FaucetUpdateConfig(ip *InputMap) (err error) {
   889  
   890  	err = t.createSmartContractTxn(FaucetSmartContractAddress,
   891  		transaction.FAUCETSC_UPDATE_SETTINGS, ip, 0)
   892  	if err != nil {
   893  		logging.Error(err)
   894  		return
   895  	}
   896  	go func() { t.setNonceAndSubmit() }()
   897  	return
   898  }
   899  
   900  //
   901  // miner SC
   902  //
   903  
   904  func (t *Transaction) MinerScUpdateConfig(ip *InputMap) (err error) {
   905  	err = t.createSmartContractTxn(MinerSmartContractAddress,
   906  		transaction.MINERSC_UPDATE_SETTINGS, ip, 0)
   907  	if err != nil {
   908  		logging.Error(err)
   909  		return
   910  	}
   911  	go func() { t.setNonceAndSubmit() }()
   912  	return
   913  }
   914  
   915  func (t *Transaction) MinerScUpdateGlobals(ip *InputMap) (err error) {
   916  	err = t.createSmartContractTxn(MinerSmartContractAddress,
   917  		transaction.MINERSC_UPDATE_GLOBALS, ip, 0)
   918  	if err != nil {
   919  		logging.Error(err)
   920  		return
   921  	}
   922  	go func() { t.setNonceAndSubmit() }()
   923  	return
   924  }
   925  
   926  func (t *Transaction) StorageScUpdateConfig(ip *InputMap) (err error) {
   927  	err = t.createSmartContractTxn(StorageSmartContractAddress,
   928  		transaction.STORAGESC_UPDATE_SETTINGS, ip, 0)
   929  	if err != nil {
   930  		logging.Error(err)
   931  		return
   932  	}
   933  	go func() { t.setNonceAndSubmit() }()
   934  	return
   935  }
   936  func (t *Transaction) AddHardfork(ip *InputMap) (err error) {
   937  	err = t.createSmartContractTxn(MinerSmartContractAddress,
   938  		transaction.ADD_HARDFORK, ip, 0)
   939  	if err != nil {
   940  		logging.Error(err)
   941  		return
   942  	}
   943  	go func() { t.setNonceAndSubmit() }()
   944  	return
   945  }
   946  
   947  func (t *Transaction) ZCNSCUpdateGlobalConfig(ip *InputMap) (err error) {
   948  	err = t.createSmartContractTxn(ZCNSCSmartContractAddress, transaction.ZCNSC_UPDATE_GLOBAL_CONFIG, ip, 0)
   949  	if err != nil {
   950  		logging.Error(err)
   951  		return
   952  	}
   953  	go t.setNonceAndSubmit()
   954  	return
   955  }
   956  
   957  func (t *Transaction) GetVerifyConfirmationStatus() ConfirmationStatus {
   958  	return ConfirmationStatus(t.verifyConfirmationStatus)
   959  }
   960  
   961  // RegisterMultiSig register a multisig wallet with the SC.
   962  func (t *Transaction) RegisterMultiSig(walletstr string, mswallet string) error {
   963  	w, err := GetWallet(walletstr)
   964  	if err != nil {
   965  		fmt.Printf("Error while parsing the wallet. %v\n", err)
   966  		return err
   967  	}
   968  
   969  	msw, err := GetMultisigPayload(mswallet)
   970  	if err != nil {
   971  		fmt.Printf("\nError in registering. %v\n", err)
   972  		return err
   973  	}
   974  	sn := transaction.SmartContractTxnData{Name: MultiSigRegisterFuncName, InputArgs: msw}
   975  	snBytes, err := json.Marshal(sn)
   976  	if err != nil {
   977  		return errors.Wrap(err, "execute multisig register failed due to invalid data.")
   978  	}
   979  	go func() {
   980  		t.txn.TransactionType = transaction.TxnTypeSmartContract
   981  		t.txn.ToClientID = MultiSigSmartContractAddress
   982  		t.txn.TransactionData = string(snBytes)
   983  		t.txn.Value = 0
   984  		nonce := t.txn.TransactionNonce
   985  		if nonce < 1 {
   986  			nonce = node.Cache.GetNextNonce(t.txn.ClientID)
   987  		} else {
   988  			node.Cache.Set(t.txn.ClientID, nonce)
   989  		}
   990  		t.txn.TransactionNonce = nonce
   991  
   992  		if t.txn.TransactionFee == 0 {
   993  			fee, err := transaction.EstimateFee(t.txn, _config.chain.Miners, 0.2)
   994  			if err != nil {
   995  				return
   996  			}
   997  			t.txn.TransactionFee = fee
   998  		}
   999  
  1000  		err = t.txn.ComputeHashAndSignWithWallet(signWithWallet, w)
  1001  		if err != nil {
  1002  			return
  1003  		}
  1004  		t.submitTxn()
  1005  	}()
  1006  	return nil
  1007  }
  1008  
  1009  // NewMSTransaction new transaction object for multisig operation
  1010  func NewMSTransaction(walletstr string, cb TransactionCallback) (*Transaction, error) {
  1011  	w, err := GetWallet(walletstr)
  1012  	if err != nil {
  1013  		fmt.Printf("Error while parsing the wallet. %v", err)
  1014  		return nil, err
  1015  	}
  1016  	t := &Transaction{}
  1017  	t.txn = transaction.NewTransactionEntity(w.ClientID, _config.chain.ChainID, w.ClientKey, w.Nonce)
  1018  	t.txnStatus, t.verifyStatus = StatusUnknown, StatusUnknown
  1019  	t.txnCb = cb
  1020  	return t, nil
  1021  }
  1022  
  1023  // RegisterVote register a multisig wallet with the SC.
  1024  func (t *Transaction) RegisterVote(signerwalletstr string, msvstr string) error {
  1025  
  1026  	w, err := GetWallet(signerwalletstr)
  1027  	if err != nil {
  1028  		fmt.Printf("Error while parsing the wallet. %v", err)
  1029  		return err
  1030  	}
  1031  
  1032  	msv, err := GetMultisigVotePayload(msvstr)
  1033  
  1034  	if err != nil {
  1035  		fmt.Printf("\nError in voting. %v\n", err)
  1036  		return err
  1037  	}
  1038  	sn := transaction.SmartContractTxnData{Name: MultiSigVoteFuncName, InputArgs: msv}
  1039  	snBytes, err := json.Marshal(sn)
  1040  	if err != nil {
  1041  		return errors.Wrap(err, "execute multisig vote failed due to invalid data.")
  1042  	}
  1043  	go func() {
  1044  		t.txn.TransactionType = transaction.TxnTypeSmartContract
  1045  		t.txn.ToClientID = MultiSigSmartContractAddress
  1046  		t.txn.TransactionData = string(snBytes)
  1047  		t.txn.Value = 0
  1048  		nonce := t.txn.TransactionNonce
  1049  		if nonce < 1 {
  1050  			nonce = node.Cache.GetNextNonce(t.txn.ClientID)
  1051  		} else {
  1052  			node.Cache.Set(t.txn.ClientID, nonce)
  1053  		}
  1054  		t.txn.TransactionNonce = nonce
  1055  
  1056  		if t.txn.TransactionFee == 0 {
  1057  			fee, err := transaction.EstimateFee(t.txn, _config.chain.Miners, 0.2)
  1058  			if err != nil {
  1059  				return
  1060  			}
  1061  			t.txn.TransactionFee = fee
  1062  		}
  1063  
  1064  		err = t.txn.ComputeHashAndSignWithWallet(signWithWallet, w)
  1065  		if err != nil {
  1066  			return
  1067  		}
  1068  		t.submitTxn()
  1069  	}()
  1070  	return nil
  1071  }
  1072  
  1073  type MinerSCDelegatePool struct {
  1074  	Settings StakePoolSettings `json:"settings"`
  1075  }
  1076  
  1077  // SimpleMiner represents a node in the network, miner or sharder.
  1078  type SimpleMiner struct {
  1079  	ID string `json:"id"`
  1080  }
  1081  
  1082  // MinerSCMinerInfo interface for miner/sharder info functions on miner smart contract.
  1083  type MinerSCMinerInfo struct {
  1084  	SimpleMiner         `json:"simple_miner"`
  1085  	MinerSCDelegatePool `json:"stake_pool"`
  1086  }
  1087  
  1088  func (t *Transaction) MinerSCMinerSettings(info *MinerSCMinerInfo) (err error) {
  1089  	err = t.createSmartContractTxn(MinerSmartContractAddress,
  1090  		transaction.MINERSC_MINER_SETTINGS, info, 0)
  1091  	if err != nil {
  1092  		logging.Error(err)
  1093  		return
  1094  	}
  1095  	go func() { t.setNonceAndSubmit() }()
  1096  	return
  1097  }
  1098  
  1099  func (t *Transaction) MinerSCSharderSettings(info *MinerSCMinerInfo) (err error) {
  1100  	err = t.createSmartContractTxn(MinerSmartContractAddress,
  1101  		transaction.MINERSC_SHARDER_SETTINGS, info, 0)
  1102  	if err != nil {
  1103  		logging.Error(err)
  1104  		return
  1105  	}
  1106  	go func() { t.setNonceAndSubmit() }()
  1107  	return
  1108  }
  1109  
  1110  func (t *Transaction) MinerSCDeleteMiner(info *MinerSCMinerInfo) (err error) {
  1111  	err = t.createSmartContractTxn(MinerSmartContractAddress,
  1112  		transaction.MINERSC_MINER_DELETE, info, 0)
  1113  	if err != nil {
  1114  		logging.Error(err)
  1115  		return
  1116  	}
  1117  	go func() { t.setNonceAndSubmit() }()
  1118  	return
  1119  }
  1120  
  1121  func (t *Transaction) MinerSCDeleteSharder(info *MinerSCMinerInfo) (err error) {
  1122  	err = t.createSmartContractTxn(MinerSmartContractAddress,
  1123  		transaction.MINERSC_SHARDER_DELETE, info, 0)
  1124  	if err != nil {
  1125  		logging.Error(err)
  1126  		return
  1127  	}
  1128  	go func() { t.setNonceAndSubmit() }()
  1129  	return
  1130  }
  1131  
  1132  // AuthorizerNode represents an authorizer node in the network
  1133  type AuthorizerNode struct {
  1134  	ID     string            `json:"id"`
  1135  	URL    string            `json:"url"`
  1136  	Config *AuthorizerConfig `json:"config"`
  1137  }
  1138  
  1139  func (t *Transaction) ZCNSCUpdateAuthorizerConfig(ip *AuthorizerNode) (err error) {
  1140  	err = t.createSmartContractTxn(ZCNSCSmartContractAddress, transaction.ZCNSC_UPDATE_AUTHORIZER_CONFIG, ip, 0)
  1141  	if err != nil {
  1142  		logging.Error(err)
  1143  		return
  1144  	}
  1145  	go t.setNonceAndSubmit()
  1146  	return
  1147  }
  1148  
  1149  func (t *Transaction) Verify() error {
  1150  	if t.txnHash == "" && t.txnStatus == StatusUnknown {
  1151  		return errors.New("", "invalid transaction. cannot be verified.")
  1152  	}
  1153  	if t.txnHash == "" && t.txnStatus == StatusSuccess {
  1154  		h := t.GetTransactionHash()
  1155  		if h == "" {
  1156  			node.Cache.Evict(t.txn.ClientID)
  1157  			return errors.New("", "invalid transaction. cannot be verified.")
  1158  		}
  1159  	}
  1160  	// If transaction is verify only start from current time
  1161  	if t.txn.CreationDate == 0 {
  1162  		t.txn.CreationDate = int64(common.Now())
  1163  	}
  1164  
  1165  	tq, err := NewTransactionQuery(Sharders.Healthy(), _config.chain.Miners)
  1166  	if err != nil {
  1167  		logging.Error(err)
  1168  		return err
  1169  	}
  1170  
  1171  	go func() {
  1172  
  1173  		for {
  1174  
  1175  			tq.Reset()
  1176  			// Get transaction confirmationBlock from a random sharder
  1177  			confirmBlockHeader, confirmationBlock, lfbBlockHeader, err := tq.getFastConfirmation(context.TODO(), t.txnHash)
  1178  			if err != nil {
  1179  				now := int64(common.Now())
  1180  
  1181  				// maybe it is a network or server error
  1182  				if lfbBlockHeader == nil {
  1183  					logging.Info(err, " now: ", now)
  1184  				} else {
  1185  					logging.Info(err, " now: ", now, ", LFB creation time:", lfbBlockHeader.CreationDate)
  1186  				}
  1187  
  1188  				// transaction is done or expired. it means random sharder might be outdated, try to query it from s/S sharders to confirm it
  1189  				if util.MaxInt64(lfbBlockHeader.getCreationDate(now), now) >= (t.txn.CreationDate + int64(defaultTxnExpirationSeconds)) {
  1190  					logging.Info("falling back to ", getMinShardersVerify(), " of ", len(_config.chain.Sharders), " Sharders")
  1191  					confirmBlockHeader, confirmationBlock, lfbBlockHeader, err = tq.getConsensusConfirmation(context.TODO(), getMinShardersVerify(), t.txnHash)
  1192  				}
  1193  
  1194  				// txn not found in fast confirmation/consensus confirmation
  1195  				if err != nil {
  1196  
  1197  					if lfbBlockHeader == nil {
  1198  						// no any valid lfb on all sharders. maybe they are network/server errors. try it again
  1199  						continue
  1200  					}
  1201  
  1202  					// it is expired
  1203  					if t.isTransactionExpired(lfbBlockHeader.getCreationDate(now), now) {
  1204  						t.completeVerify(StatusError, "", errors.New("", `{"error": "verify transaction failed"}`))
  1205  						return
  1206  					}
  1207  					continue
  1208  				}
  1209  			}
  1210  
  1211  			valid := validateChain(confirmBlockHeader)
  1212  			if valid {
  1213  				output, err := json.Marshal(confirmationBlock)
  1214  				if err != nil {
  1215  					t.completeVerify(StatusError, "", errors.New("", `{"error": "transaction confirmation json marshal error"`))
  1216  					return
  1217  				}
  1218  				confJson := confirmationBlock["confirmation"]
  1219  
  1220  				var conf map[string]json.RawMessage
  1221  				if err := json.Unmarshal(confJson, &conf); err != nil {
  1222  					return
  1223  				}
  1224  				txnJson := conf["txn"]
  1225  
  1226  				tt := transaction.Transaction{}
  1227  				if err := json.Unmarshal(txnJson, &tt); err != nil {
  1228  					return
  1229  				}
  1230  
  1231  				*t.txn = tt
  1232  				txStatus := tt.Status
  1233  
  1234  				switch txStatus {
  1235  				case 1:
  1236  					t.completeVerifyWithConStatus(StatusSuccess, int(Success), string(output), nil)
  1237  				case 2:
  1238  					t.completeVerifyWithConStatus(StatusSuccess, int(ChargeableError), tt.TransactionOutput, nil)
  1239  				default:
  1240  					t.completeVerify(StatusError, string(output), nil)
  1241  				}
  1242  				return
  1243  			}
  1244  		}
  1245  	}()
  1246  	return nil
  1247  }
  1248  
  1249  // ConvertToValue converts ZCN tokens to SAS tokens
  1250  // # Inputs
  1251  //   - token: ZCN tokens
  1252  func ConvertToValue(token float64) uint64 {
  1253  	return uint64(token * common.TokenUnit)
  1254  }
  1255  
  1256  func GetLatestFinalized(ctx context.Context, numSharders int) (b *block.Header, err error) {
  1257  	var result = make(chan *util.GetResponse, numSharders)
  1258  	defer close(result)
  1259  
  1260  	numSharders = len(Sharders.Healthy()) // overwrite, use all
  1261  	Sharders.QueryFromShardersContext(ctx, numSharders, GET_LATEST_FINALIZED, result)
  1262  
  1263  	var (
  1264  		maxConsensus   int
  1265  		roundConsensus = make(map[string]int)
  1266  	)
  1267  
  1268  	for i := 0; i < numSharders; i++ {
  1269  		var rsp = <-result
  1270  		if rsp == nil {
  1271  			logging.Error("nil response")
  1272  			continue
  1273  		}
  1274  
  1275  		logging.Debug(rsp.Url, rsp.Status)
  1276  
  1277  		if rsp.StatusCode != http.StatusOK {
  1278  			logging.Error(rsp.Body)
  1279  			continue
  1280  		}
  1281  
  1282  		if err = json.Unmarshal([]byte(rsp.Body), &b); err != nil {
  1283  			logging.Error("block parse error: ", err)
  1284  			err = nil
  1285  			continue
  1286  		}
  1287  
  1288  		var h = encryption.FastHash([]byte(b.Hash))
  1289  		if roundConsensus[h]++; roundConsensus[h] > maxConsensus {
  1290  			maxConsensus = roundConsensus[h]
  1291  		}
  1292  	}
  1293  
  1294  	if maxConsensus == 0 {
  1295  		return nil, errors.New("", "block info not found")
  1296  	}
  1297  
  1298  	return
  1299  }
  1300  
  1301  // GetLatestFinalizedMagicBlock gets latest finalized magic block
  1302  //   - numSharders: number of sharders
  1303  //   - timeout: request timeout
  1304  func GetLatestFinalizedMagicBlock(ctx context.Context, numSharders int) (m *block.MagicBlock, err error) {
  1305  	var result = make(chan *util.GetResponse, numSharders)
  1306  	defer close(result)
  1307  
  1308  	numSharders = len(Sharders.Healthy()) // overwrite, use all
  1309  	Sharders.QueryFromShardersContext(ctx, numSharders, GET_LATEST_FINALIZED_MAGIC_BLOCK, result)
  1310  
  1311  	var (
  1312  		maxConsensus   int
  1313  		roundConsensus = make(map[string]int)
  1314  	)
  1315  
  1316  	type respObj struct {
  1317  		MagicBlock *block.MagicBlock `json:"magic_block"`
  1318  	}
  1319  
  1320  	for i := 0; i < numSharders; i++ {
  1321  		var rsp = <-result
  1322  		if rsp == nil {
  1323  			logging.Error("nil response")
  1324  			continue
  1325  		}
  1326  
  1327  		logging.Debug(rsp.Url, rsp.Status)
  1328  
  1329  		if rsp.StatusCode != http.StatusOK {
  1330  			logging.Error(rsp.Body)
  1331  			continue
  1332  		}
  1333  
  1334  		var respo respObj
  1335  		if err = json.Unmarshal([]byte(rsp.Body), &respo); err != nil {
  1336  			logging.Error(" magic block parse error: ", err)
  1337  			err = nil
  1338  			continue
  1339  		}
  1340  
  1341  		m = respo.MagicBlock
  1342  		var h = encryption.FastHash([]byte(respo.MagicBlock.Hash))
  1343  		if roundConsensus[h]++; roundConsensus[h] > maxConsensus {
  1344  			maxConsensus = roundConsensus[h]
  1345  		}
  1346  	}
  1347  
  1348  	if maxConsensus == 0 {
  1349  		return nil, errors.New("", "magic block info not found")
  1350  	}
  1351  
  1352  	return
  1353  }
  1354  
  1355  func GetChainStats(ctx context.Context) (b *block.ChainStats, err error) {
  1356  	var result = make(chan *util.GetResponse, 1)
  1357  	defer close(result)
  1358  
  1359  	var numSharders = len(Sharders.Healthy()) // overwrite, use all
  1360  	Sharders.QueryFromShardersContext(ctx, numSharders, GET_CHAIN_STATS, result)
  1361  	var rsp *util.GetResponse
  1362  	for i := 0; i < numSharders; i++ {
  1363  		var x = <-result
  1364  		if x == nil {
  1365  			logging.Error("nil response")
  1366  			continue
  1367  		}
  1368  		if x.StatusCode != http.StatusOK {
  1369  			continue
  1370  		}
  1371  		rsp = x
  1372  	}
  1373  
  1374  	if rsp == nil {
  1375  		return nil, errors.New("http_request_failed", "Request failed with status not 200")
  1376  	}
  1377  
  1378  	if err = json.Unmarshal([]byte(rsp.Body), &b); err != nil {
  1379  		return nil, err
  1380  	}
  1381  	return
  1382  }
  1383  
  1384  func GetFeeStats(ctx context.Context) (b *block.FeeStats, err error) {
  1385  
  1386  	var numMiners = 4
  1387  
  1388  	if numMiners > len(_config.chain.Miners) {
  1389  		numMiners = len(_config.chain.Miners)
  1390  	}
  1391  
  1392  	var result = make(chan *util.GetResponse, numMiners)
  1393  
  1394  	queryFromMinersContext(ctx, numMiners, GET_FEE_STATS, result)
  1395  	var rsp *util.GetResponse
  1396  
  1397  loop:
  1398  	for i := 0; i < numMiners; i++ {
  1399  		select {
  1400  		case x := <-result:
  1401  			if x.StatusCode != http.StatusOK {
  1402  				continue
  1403  			}
  1404  			rsp = x
  1405  			if rsp != nil {
  1406  				break loop
  1407  			}
  1408  		case <-ctx.Done():
  1409  			err = ctx.Err()
  1410  			return nil, err
  1411  		}
  1412  	}
  1413  	if rsp == nil {
  1414  		return nil, errors.New("http_request_failed", "Request failed with status not 200")
  1415  	}
  1416  	if err = json.Unmarshal([]byte(rsp.Body), &b); err != nil {
  1417  		return nil, err
  1418  	}
  1419  	return
  1420  }
  1421  
  1422  func GetBlockByRound(ctx context.Context, numSharders int, round int64) (b *block.Block, err error) {
  1423  	return Sharders.GetBlockByRound(ctx, numSharders, round)
  1424  }
  1425  
  1426  // GetRoundFromSharders returns the current round number from the sharders
  1427  func GetRoundFromSharders() (int64, error) {
  1428  	return Sharders.GetRoundFromSharders()
  1429  }
  1430  
  1431  // GetHardForkRound returns the round number of the hard fork
  1432  //   - hardFork: hard fork name
  1433  func GetHardForkRound(hardFork string) (int64, error) {
  1434  	return Sharders.GetHardForkRound(hardFork)
  1435  }
  1436  
  1437  func GetMagicBlockByNumber(ctx context.Context, numSharders int, number int64) (m *block.MagicBlock, err error) {
  1438  
  1439  	var result = make(chan *util.GetResponse, numSharders)
  1440  	defer close(result)
  1441  
  1442  	numSharders = len(Sharders.Healthy()) // overwrite, use all
  1443  	Sharders.QueryFromShardersContext(ctx, numSharders,
  1444  		fmt.Sprintf("%smagic_block_number=%d", GET_MAGIC_BLOCK_INFO, number),
  1445  		result)
  1446  
  1447  	var (
  1448  		maxConsensus   int
  1449  		roundConsensus = make(map[string]int)
  1450  	)
  1451  
  1452  	type respObj struct {
  1453  		MagicBlock *block.MagicBlock `json:"magic_block"`
  1454  	}
  1455  
  1456  	for i := 0; i < numSharders; i++ {
  1457  		var rsp = <-result
  1458  		if rsp == nil {
  1459  			logging.Error("nil response")
  1460  			continue
  1461  		}
  1462  		logging.Debug(rsp.Url, rsp.Status)
  1463  
  1464  		if rsp.StatusCode != http.StatusOK {
  1465  			logging.Error(rsp.Body)
  1466  			continue
  1467  		}
  1468  
  1469  		var respo respObj
  1470  		if err = json.Unmarshal([]byte(rsp.Body), &respo); err != nil {
  1471  			logging.Error(" magic block parse error: ", err)
  1472  			err = nil
  1473  			continue
  1474  		}
  1475  
  1476  		m = respo.MagicBlock
  1477  		var h = encryption.FastHash([]byte(respo.MagicBlock.Hash))
  1478  		if roundConsensus[h]++; roundConsensus[h] > maxConsensus {
  1479  			maxConsensus = roundConsensus[h]
  1480  		}
  1481  	}
  1482  
  1483  	if maxConsensus == 0 {
  1484  		return nil, errors.New("", "magic block info not found")
  1485  	}
  1486  
  1487  	return
  1488  }
  1489  
  1490  type NonceCache struct {
  1491  	cache map[string]int64
  1492  	guard sync.Mutex
  1493  }
  1494  
  1495  func NewNonceCache() *NonceCache {
  1496  	return &NonceCache{cache: make(map[string]int64)}
  1497  }
  1498  
  1499  func (nc *NonceCache) GetNextNonce(clientId string) int64 {
  1500  	nc.guard.Lock()
  1501  	defer nc.guard.Unlock()
  1502  	if _, ok := nc.cache[clientId]; !ok {
  1503  		back := &getNonceCallBack{
  1504  			nonceCh: make(chan int64),
  1505  			err:     nil,
  1506  		}
  1507  		if err := GetNonce(back); err != nil {
  1508  			return 0
  1509  		}
  1510  
  1511  		timeout, cancel := context.WithTimeout(context.Background(), time.Second)
  1512  		defer cancel()
  1513  		select {
  1514  		case n := <-back.nonceCh:
  1515  			if back.err != nil {
  1516  				return 0
  1517  			}
  1518  			nc.cache[clientId] = n
  1519  		case <-timeout.Done():
  1520  			return 0
  1521  		}
  1522  	}
  1523  
  1524  	nc.cache[clientId] += 1
  1525  	return nc.cache[clientId]
  1526  }
  1527  
  1528  func (nc *NonceCache) Set(clientId string, nonce int64) {
  1529  	nc.guard.Lock()
  1530  	defer nc.guard.Unlock()
  1531  	nc.cache[clientId] = nonce
  1532  }
  1533  
  1534  func (nc *NonceCache) Evict(clientId string) {
  1535  	nc.guard.Lock()
  1536  	defer nc.guard.Unlock()
  1537  	delete(nc.cache, clientId)
  1538  }
  1539  
  1540  // WithEthereumNode set the ethereum node used for bridge operations.
  1541  //   - uri: ethereum node uri
  1542  func WithEthereumNode(uri string) func(c *ChainConfig) error {
  1543  	return func(c *ChainConfig) error {
  1544  		c.EthNode = uri
  1545  		return nil
  1546  	}
  1547  }
  1548  
  1549  // WithChainID set the chain id. Chain ID is a unique identifier for the blockchain which is set at the time of its creation.
  1550  //   - id: chain id
  1551  func WithChainID(id string) func(c *ChainConfig) error {
  1552  	return func(c *ChainConfig) error {
  1553  		c.ChainID = id
  1554  		return nil
  1555  	}
  1556  }
  1557  
  1558  // WithMinSubmit set the minimum submit, minimum number of miners that should receive the transaction submission.
  1559  //   - m: minimum submit
  1560  func WithMinSubmit(m int) func(c *ChainConfig) error {
  1561  	return func(c *ChainConfig) error {
  1562  		c.MinSubmit = m
  1563  		return nil
  1564  	}
  1565  }
  1566  
  1567  // WithMinConfirmation set the minimum confirmation, minimum number of nodes that should confirm the transaction.
  1568  //   - m: minimum confirmation
  1569  func WithMinConfirmation(m int) func(c *ChainConfig) error {
  1570  	return func(c *ChainConfig) error {
  1571  		c.MinConfirmation = m
  1572  		return nil
  1573  	}
  1574  }
  1575  
  1576  // WithConfirmationChainLength set the confirmation chain length, which is the number of blocks that need to be confirmed.
  1577  //   - m: confirmation chain length
  1578  func WithConfirmationChainLength(m int) func(c *ChainConfig) error {
  1579  	return func(c *ChainConfig) error {
  1580  		c.ConfirmationChainLength = m
  1581  		return nil
  1582  	}
  1583  }
  1584  
  1585  func WithSharderConsensous(m int) func(c *ChainConfig) error {
  1586  	return func(c *ChainConfig) error {
  1587  		c.SharderConsensous = m
  1588  		return nil
  1589  	}
  1590  }
  1591  
  1592  func WithIsSplitWallet(v bool) func(c *ChainConfig) error {
  1593  	return func(c *ChainConfig) error {
  1594  		c.IsSplitWallet = v
  1595  		return nil
  1596  	}
  1597  }
  1598  
  1599  // UpdateValidatorSettings update settings of a validator.
  1600  func (t *Transaction) UpdateValidatorSettings(v *Validator) (err error) {
  1601  
  1602  	err = t.createSmartContractTxn(StorageSmartContractAddress,
  1603  		transaction.STORAGESC_UPDATE_VALIDATOR_SETTINGS, v, 0)
  1604  	if err != nil {
  1605  		logging.Error(err)
  1606  		return
  1607  	}
  1608  	go func() { t.setNonceAndSubmit() }()
  1609  	return
  1610  }
  1611  
  1612  type VestingClientList struct {
  1613  	Pools []common.Key `json:"pools"`
  1614  }
  1615  
  1616  func GetVestingClientList(clientID string, cb GetInfoCallback) (err error) {
  1617  	if err = CheckConfig(); err != nil {
  1618  		return
  1619  	}
  1620  	if clientID == "" {
  1621  		clientID = _config.wallet.ClientID // if not blank
  1622  	}
  1623  	go GetInfoFromSharders(WithParams(GET_VESTING_CLIENT_POOLS, Params{
  1624  		"client_id": clientID,
  1625  	}), 0, cb)
  1626  	return
  1627  }
  1628  
  1629  type VestingDestInfo struct {
  1630  	ID     common.Key       `json:"id"`     // identifier
  1631  	Wanted common.Balance   `json:"wanted"` // wanted amount for entire period
  1632  	Earned common.Balance   `json:"earned"` // can unlock
  1633  	Vested common.Balance   `json:"vested"` // already vested
  1634  	Last   common.Timestamp `json:"last"`   // last time unlocked
  1635  }
  1636  
  1637  type VestingPoolInfo struct {
  1638  	ID           common.Key         `json:"pool_id"`      // pool ID
  1639  	Balance      common.Balance     `json:"balance"`      // real pool balance
  1640  	Left         common.Balance     `json:"left"`         // owner can unlock
  1641  	Description  string             `json:"description"`  // description
  1642  	StartTime    common.Timestamp   `json:"start_time"`   // from
  1643  	ExpireAt     common.Timestamp   `json:"expire_at"`    // until
  1644  	Destinations []*VestingDestInfo `json:"destinations"` // receivers
  1645  	ClientID     common.Key         `json:"client_id"`    // owner
  1646  }
  1647  
  1648  func GetVestingPoolInfo(poolID string, cb GetInfoCallback) (err error) {
  1649  	if err = CheckConfig(); err != nil {
  1650  		return
  1651  	}
  1652  	GetInfoFromSharders(WithParams(GET_VESTING_POOL_INFO, Params{
  1653  		"pool_id": poolID,
  1654  	}), 0, cb)
  1655  	return
  1656  }
  1657  
  1658  func GetVestingSCConfig(cb GetInfoCallback) (err error) {
  1659  	if err = CheckConfig(); err != nil {
  1660  		return
  1661  	}
  1662  	go GetInfoFromSharders(GET_VESTING_CONFIG, 0, cb)
  1663  	return
  1664  }
  1665  
  1666  // faucet
  1667  
  1668  func GetFaucetSCConfig(cb GetInfoCallback) (err error) {
  1669  	if err = CheckConfig(); err != nil {
  1670  		return
  1671  	}
  1672  	go GetInfoFromSharders(GET_FAUCETSC_CONFIG, 0, cb)
  1673  	return
  1674  }
  1675  
  1676  func (t *Transaction) ZCNSCAddAuthorizer(ip *AddAuthorizerPayload) (err error) {
  1677  	err = t.createSmartContractTxn(ZCNSCSmartContractAddress, transaction.ZCNSC_ADD_AUTHORIZER, ip, 0)
  1678  	if err != nil {
  1679  		logging.Error(err)
  1680  		return
  1681  	}
  1682  	go t.setNonceAndSubmit()
  1683  	return
  1684  }
  1685  
  1686  func (t *Transaction) ZCNSCAuthorizerHealthCheck(ip *AuthorizerHealthCheckPayload) (err error) {
  1687  	err = t.createSmartContractTxn(ZCNSCSmartContractAddress, transaction.ZCNSC_AUTHORIZER_HEALTH_CHECK, ip, 0)
  1688  	if err != nil {
  1689  		logging.Error(err)
  1690  		return
  1691  	}
  1692  	go t.setNonceAndSubmit()
  1693  	return
  1694  }
  1695  
  1696  func (t *Transaction) ZCNSCDeleteAuthorizer(ip *DeleteAuthorizerPayload) (err error) {
  1697  	err = t.createSmartContractTxn(ZCNSCSmartContractAddress, transaction.ZCNSC_DELETE_AUTHORIZER, ip, 0)
  1698  	if err != nil {
  1699  		logging.Error(err)
  1700  		return
  1701  	}
  1702  	go t.setNonceAndSubmit()
  1703  	return
  1704  }
  1705  
  1706  func (t *Transaction) ZCNSCCollectReward(providerId string, providerType Provider) error {
  1707  	pr := &scCollectReward{
  1708  		ProviderId:   providerId,
  1709  		ProviderType: int(providerType),
  1710  	}
  1711  	err := t.createSmartContractTxn(ZCNSCSmartContractAddress,
  1712  		transaction.ZCNSC_COLLECT_REWARD, pr, 0)
  1713  	if err != nil {
  1714  		logging.Error(err)
  1715  		return err
  1716  	}
  1717  	go func() { t.setNonceAndSubmit() }()
  1718  	return err
  1719  }