Skip to content

Commit

Permalink
Merge pull request #1626
Browse files Browse the repository at this point in the history
Fix: move transaction scheme to mobile package
  • Loading branch information
dabasov authored Sep 26, 2024
2 parents 3c24296 + 9668750 commit e1a968e
Show file tree
Hide file tree
Showing 11 changed files with 636 additions and 478 deletions.
20 changes: 0 additions & 20 deletions core/transaction/entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,26 +26,6 @@ const (
TxnFail = 3 // Indicates a transaction has failed to update the state or smart contract
)

// Transaction entity that encapsulates the transaction related data and meta data
type Transaction struct {
Hash string `json:"hash,omitempty"`
Version string `json:"version,omitempty"`
ClientID string `json:"client_id,omitempty"`
PublicKey string `json:"public_key,omitempty"`
ToClientID string `json:"to_client_id,omitempty"`
ChainID string `json:"chain_id,omitempty"`
TransactionData string `json:"transaction_data"`
Value uint64 `json:"transaction_value"`
Signature string `json:"signature,omitempty"`
CreationDate int64 `json:"creation_date,omitempty"`
TransactionType int `json:"transaction_type"`
TransactionOutput string `json:"transaction_output,omitempty"`
TransactionFee uint64 `json:"transaction_fee"`
TransactionNonce int64 `json:"transaction_nonce"`
OutputHash string `json:"txn_output_hash"`
Status int `json:"transaction_status"`
}

// TxnReceipt - a transaction receipt is a processed transaction that contains the output
type TxnReceipt struct {
Transaction *Transaction
Expand Down
24 changes: 24 additions & 0 deletions core/transaction/transaction.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//go:build !mobile
// +build !mobile

package transaction

// Transaction entity that encapsulates the transaction related data and meta data
type Transaction struct {
Hash string `json:"hash,omitempty"`
Version string `json:"version,omitempty"`
ClientID string `json:"client_id,omitempty"`
PublicKey string `json:"public_key,omitempty"`
ToClientID string `json:"to_client_id,omitempty"`
ChainID string `json:"chain_id,omitempty"`
TransactionData string `json:"transaction_data"`
Value uint64 `json:"transaction_value"`
Signature string `json:"signature,omitempty"`
CreationDate int64 `json:"creation_date,omitempty"`
TransactionType int `json:"transaction_type"`
TransactionOutput string `json:"transaction_output,omitempty"`
TransactionFee uint64 `json:"transaction_fee"`
TransactionNonce int64 `json:"transaction_nonce"`
OutputHash string `json:"txn_output_hash"`
Status int `json:"transaction_status"`
}
82 changes: 82 additions & 0 deletions core/transaction/transaction_mobile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//go:build mobile
// +build mobile

package transaction

import (
"encoding/json"
"strconv"
)

// Transaction represents entity that encapsulates the transaction related data and metadata.
type Transaction struct {
Hash string `json:"hash,omitempty"`
Version string `json:"version,omitempty"`
ClientID string `json:"client_id,omitempty"`
PublicKey string `json:"public_key,omitempty"`
ToClientID string `json:"to_client_id,omitempty"`
ChainID string `json:"chain_id,omitempty"`
TransactionData string `json:"transaction_data"`
Value string `json:"transaction_value"`
Signature string `json:"signature,omitempty"`
CreationDate int64 `json:"creation_date,omitempty"`
TransactionType int `json:"transaction_type"`
TransactionOutput string `json:"transaction_output,omitempty"`
TransactionFee string `json:"transaction_fee"`
TransactionNonce int64 `json:"transaction_nonce"`
OutputHash string `json:"txn_output_hash"`
Status int `json:"transaction_status"`
}

// TransactionWrapper represents wrapper for mobile transaction entity.
type TransactionWrapper struct {
Hash string `json:"hash,omitempty"`
Version string `json:"version,omitempty"`
ClientID string `json:"client_id,omitempty"`
PublicKey string `json:"public_key,omitempty"`
ToClientID string `json:"to_client_id,omitempty"`
ChainID string `json:"chain_id,omitempty"`
TransactionData string `json:"transaction_data"`
Value uint64 `json:"transaction_value"`
Signature string `json:"signature,omitempty"`
CreationDate int64 `json:"creation_date,omitempty"`
TransactionType int `json:"transaction_type"`
TransactionOutput string `json:"transaction_output,omitempty"`
TransactionFee uint64 `json:"transaction_fee"`
TransactionNonce int64 `json:"transaction_nonce"`
OutputHash string `json:"txn_output_hash"`
Status int `json:"transaction_status"`
}

func (t *Transaction) MarshalJSON() ([]byte, error) {
valueRaw, err := strconv.ParseUint(t.Value, 0, 64)
if err != nil {
return nil, err
}

transactionFeeRaw, err := strconv.ParseUint(t.TransactionFee, 0, 64)
if err != nil {
return nil, err
}

wrapper := TransactionWrapper{
Hash: t.Hash,
Version: t.Version,
ClientID: t.ClientID,
PublicKey: t.PublicKey,
ToClientID: t.ToClientID,
ChainID: t.ChainID,
TransactionData: t.TransactionData,
Value: valueRaw,
Signature: t.Signature,
CreationDate: t.CreationDate,
TransactionType: t.TransactionType,
TransactionOutput: t.TransactionOutput,
TransactionFee: transactionFeeRaw,
TransactionNonce: t.TransactionNonce,
OutputHash: t.OutputHash,
Status: t.Status,
}

return json.Marshal(wrapper)
}
2 changes: 1 addition & 1 deletion mobilesdk/zcn/smartcontract.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func ExecuteSmartContract(address, methodName, input, sasToken string) (string,

wg.Add(1)

_, err = txn.ExecuteSmartContract(address, methodName, input, sasToken)
err = txn.ExecuteSmartContract(address, methodName, input, sasToken)
if err != nil {
return "", err

Expand Down
10 changes: 9 additions & 1 deletion zboxcore/sdk/transaction_mobile.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,19 @@ func ExecuteSmartContract(address string, sn transaction.SmartContractTxnData, v
}

wg.Add(1)
t, err := txn.ExecuteSmartContract(address, sn.Name, sn.InputArgs, value)

inputRaw, ok := sn.InputArgs.(string)
if !ok {
return nil, fmt.Errorf("failed to convert input args")
}

err = txn.ExecuteSmartContract(address, sn.Name, inputRaw, value)
if err != nil {
return nil, err
}

t := txn.GetDetails()

msg := fmt.Sprintf("Executing transaction '%s' with hash %s ", sn.Name, t.Hash)
l.Logger.Info(msg)
l.Logger.Info("estimated txn fee: ", t.TransactionFee)
Expand Down
160 changes: 160 additions & 0 deletions zcncore/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/0chain/gosdk/core/node"
"github.com/0chain/gosdk/core/transaction"
"github.com/0chain/gosdk/core/util"
"github.com/0chain/gosdk/core/zcncrypto"
)

// Provider represents the type of provider.
Expand Down Expand Up @@ -178,6 +179,57 @@ type TransactionCommon interface {
ZCNSCCollectReward(providerID string, providerType Provider) error
}

// compiler time check
var (
_ TransactionScheme = (*Transaction)(nil)
_ TransactionScheme = (*TransactionWithAuth)(nil)
)

// TransactionScheme implements few methods for block chain.
//
// Note: to be buildable on MacOSX all arguments should have names.
type TransactionScheme interface {
TransactionCommon
// SetTransactionCallback implements storing the callback
// used to call after the transaction or verification is completed
SetTransactionCallback(cb TransactionCallback) error
// StoreData implements store the data to blockchain
StoreData(data string) error
// ExecuteFaucetSCWallet implements the `Faucet Smart contract` for a given wallet
ExecuteFaucetSCWallet(walletStr string, methodName string, input []byte) error
// GetTransactionHash implements retrieval of hash of the submitted transaction
GetTransactionHash() string
// SetTransactionHash implements verify a previous transaction status
SetTransactionHash(hash string) error
// SetTransactionNonce implements method to set the transaction nonce
SetTransactionNonce(txnNonce int64) error
// Verify implements verify the transaction
Verify() error
// GetVerifyOutput implements the verification output from sharders
GetVerifyOutput() string
// GetTransactionError implements error string in case of transaction failure
GetTransactionError() string
// GetVerifyError implements error string in case of verify failure error
GetVerifyError() string
// GetTransactionNonce returns nonce
GetTransactionNonce() int64

// Output of transaction.
Output() []byte

// Hash Transaction status regardless of status
Hash() string

// Vesting SC

VestingTrigger(poolID string) error
VestingStop(sr *VestingStopRequest) error
VestingUnlock(poolID string) error
VestingDelete(poolID string) error

// Miner SC
}

// PriceRange represents a price range allowed by user to filter blobbers.
type PriceRange struct {
Min common.Balance `json:"min"`
Expand Down Expand Up @@ -272,6 +324,16 @@ type InputMap struct {
Fields map[string]string `json:"Fields"`
}

func newTransaction(cb TransactionCallback, txnFee uint64, nonce int64) (*Transaction, error) {
t := &Transaction{}
t.txn = transaction.NewTransactionEntity(_config.wallet.ClientID, _config.chain.ChainID, _config.wallet.ClientKey, nonce)
t.txnStatus, t.verifyStatus = StatusUnknown, StatusUnknown
t.txnCb = cb
t.txn.TransactionNonce = nonce
t.txn.TransactionFee = txnFee
return t, nil
}

// NewTransaction new generic transaction object for any operation
// - cb: callback for transaction state
// - txnFee: Transaction fees (in SAS tokens)
Expand All @@ -290,6 +352,55 @@ func NewTransaction(cb TransactionCallback, txnFee uint64, nonce int64) (Transac
return newTransaction(cb, txnFee, nonce)
}

func (t *Transaction) createSmartContractTxn(address, methodName string, input interface{}, value uint64, opts ...FeeOption) error {
sn := transaction.SmartContractTxnData{Name: methodName, InputArgs: input}
snBytes, err := json.Marshal(sn)
if err != nil {
return errors.Wrap(err, "create smart contract failed due to invalid data")
}

t.txn.TransactionType = transaction.TxnTypeSmartContract
t.txn.ToClientID = address
t.txn.TransactionData = string(snBytes)
t.txn.Value = value

if t.txn.TransactionFee > 0 {
return nil
}

tf := &TxnFeeOption{}
for _, opt := range opts {
opt(tf)
}

if tf.noEstimateFee {
return nil
}

// TODO: check if transaction is exempt to avoid unnecessary fee estimation
minFee, err := transaction.EstimateFee(t.txn, _config.chain.Miners, 0.2)
if err != nil {
return err
}

t.txn.TransactionFee = minFee

return nil
}

func (t *Transaction) createFaucetSCWallet(walletStr string, methodName string, input []byte) (*zcncrypto.Wallet, error) {
w, err := getWallet(walletStr)
if err != nil {
fmt.Printf("Error while parsing the wallet. %v\n", err)
return nil, err
}
err = t.createSmartContractTxn(FaucetSmartContractAddress, methodName, input, 0)
if err != nil {
return nil, err
}
return w, nil
}

func (t *Transaction) ExecuteSmartContract(address, methodName string, input interface{}, val uint64, opts ...FeeOption) (*transaction.Transaction, error) {
err := t.createSmartContractTxn(address, methodName, input, val, opts...)
if err != nil {
Expand Down Expand Up @@ -376,6 +487,55 @@ func (t *Transaction) VestingAdd(ar *VestingAddRequest, value uint64) (
return
}

func (t *Transaction) VestingStop(sr *VestingStopRequest) (err error) {
err = t.createSmartContractTxn(VestingSmartContractAddress,
transaction.VESTING_STOP, sr, 0)
if err != nil {
logging.Error(err)
return
}
go func() { t.setNonceAndSubmit() }()
return
}

func (t *Transaction) vestingPoolTxn(function string, poolID string,
value uint64) error {

return t.createSmartContractTxn(VestingSmartContractAddress,
function, vestingRequest{PoolID: common.Key(poolID)}, value)
}

func (t *Transaction) VestingTrigger(poolID string) (err error) {

err = t.vestingPoolTxn(transaction.VESTING_TRIGGER, poolID, 0)
if err != nil {
logging.Error(err)
return
}
go func() { t.setNonceAndSubmit() }()
return
}

func (t *Transaction) VestingUnlock(poolID string) (err error) {
err = t.vestingPoolTxn(transaction.VESTING_UNLOCK, poolID, 0)
if err != nil {
logging.Error(err)
return
}
go func() { t.setNonceAndSubmit() }()
return
}

func (t *Transaction) VestingDelete(poolID string) (err error) {
err = t.vestingPoolTxn(transaction.VESTING_DELETE, poolID, 0)
if err != nil {
logging.Error(err)
return
}
go func() { t.setNonceAndSubmit() }()
return
}

func (t *Transaction) MinerSCLock(providerId string, providerType Provider, lock uint64) error {
if lock > math.MaxInt64 {
return errors.New("invalid_lock", "int64 overflow on lock value")
Expand Down
Loading

0 comments on commit e1a968e

Please sign in to comment.