github.com/0chain/gosdk@v1.17.11/zcnbridge/transaction/txn.go (about) 1 package transaction 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "strconv" 8 "strings" 9 10 "github.com/0chain/gosdk/core/util" 11 "github.com/0chain/gosdk/zcnbridge/errors" 12 ctime "github.com/0chain/gosdk/zcnbridge/time" 13 "github.com/0chain/gosdk/zcncore" 14 ) 15 16 var ( 17 _ zcncore.TransactionCallback = (*callback)(nil) 18 ) 19 20 type ( 21 // TransactionProvider ... 22 TransactionProvider interface { 23 NewTransactionEntity(txnFee uint64) (Transaction, error) 24 } 25 26 // transactionProvider ... 27 transactionProvider struct{} 28 29 // Transaction interface describes transaction entity. 30 Transaction interface { 31 ExecuteSmartContract(ctx context.Context, address, funcName string, input interface{}, val uint64) (string, error) 32 Verify(ctx context.Context) error 33 GetScheme() zcncore.TransactionScheme 34 GetCallback() TransactionCallbackAwaitable 35 GetTransactionOutput() string 36 GetHash() string 37 SetHash(string) 38 } 39 40 // TransactionEntity entity that encapsulates the transaction related data and metadata. 41 transactionEntity struct { 42 Hash string `json:"hash,omitempty"` 43 Version string `json:"version,omitempty"` 44 TransactionOutput string `json:"transaction_output,omitempty"` 45 scheme zcncore.TransactionScheme 46 callBack TransactionCallbackAwaitable 47 } 48 ) 49 50 type ( 51 verifyOutput struct { 52 Confirmation confirmation `json:"confirmation"` 53 } 54 55 // confirmation represents the acceptance that a transaction is included into the blockchain. 56 confirmation struct { 57 Version string `json:"version"` 58 Hash string `json:"hash"` 59 BlockHash string `json:"block_hash"` 60 PreviousBlockHash string `json:"previous_block_hash"` 61 Transaction *transactionEntity `json:"txn,omitempty"` 62 CreationDate ctime.Timestamp `json:"creation_date"` 63 MinerID string `json:"miner_id"` 64 Round int64 `json:"round"` 65 Status int `json:"transaction_status"` 66 RoundRandomSeed int64 `json:"round_random_seed"` 67 MerkleTreeRoot string `json:"merkle_tree_root"` 68 MerkleTreePath *util.MTPath `json:"merkle_tree_path"` 69 ReceiptMerkleTreeRoot string `json:"receipt_merkle_tree_root"` 70 ReceiptMerkleTreePath *util.MTPath `json:"receipt_merkle_tree_path"` 71 } 72 ) 73 74 func NewTransactionProvider() TransactionProvider { 75 return &transactionProvider{} 76 } 77 78 func (t *transactionProvider) NewTransactionEntity(txnFee uint64) (Transaction, error) { 79 return NewTransactionEntity(txnFee) 80 } 81 82 // NewTransactionEntity creates Transaction with initialized fields. 83 // Sets version, client ID, creation date, public key and creates internal zcncore.TransactionScheme. 84 func NewTransactionEntity(txnFee uint64) (Transaction, error) { 85 txn := &transactionEntity{ 86 callBack: NewStatus().(*callback), 87 } 88 zcntxn, err := zcncore.NewTransaction(txn.callBack, txnFee, 0) 89 if err != nil { 90 return nil, err 91 } 92 93 txn.scheme = zcntxn 94 95 return txn, nil 96 } 97 98 // ExecuteSmartContract executes function of smart contract with provided address. 99 // 100 // Returns hash of executed transaction. 101 func (t *transactionEntity) ExecuteSmartContract(ctx context.Context, address, funcName string, input interface{}, 102 val uint64) (string, error) { 103 const errCode = "transaction_send" 104 105 tran, err := t.scheme.ExecuteSmartContract(address, funcName, input, val) 106 t.Hash = tran.Hash 107 108 if err != nil { 109 msg := fmt.Sprintf("error while sending txn: %v", err) 110 return "", errors.New(errCode, msg) 111 } 112 113 if err := t.callBack.WaitCompleteCall(ctx); err != nil { 114 msg := fmt.Sprintf("error while sending txn: %v", err) 115 return "", errors.New(errCode, msg) 116 } 117 118 if len(t.scheme.GetTransactionError()) > 0 { 119 return "", errors.New(errCode, t.scheme.GetTransactionError()) 120 } 121 122 return t.scheme.Hash(), nil 123 } 124 125 func (t *transactionEntity) Verify(ctx context.Context) error { 126 const errCode = "transaction_verify" 127 128 err := t.scheme.Verify() 129 if err != nil { 130 msg := fmt.Sprintf("error while verifying txn: %v; txn hash: %s", err, t.scheme.GetTransactionHash()) 131 return errors.New(errCode, msg) 132 } 133 134 if err := t.callBack.WaitVerifyCall(ctx); err != nil { 135 msg := fmt.Sprintf("error while verifying txn: %v; txn hash: %s", err, t.scheme.GetTransactionHash()) 136 return errors.New(errCode, msg) 137 } 138 139 switch t.scheme.GetVerifyConfirmationStatus() { 140 case zcncore.ChargeableError: 141 return errors.New(errCode, strings.Trim(t.scheme.GetVerifyOutput(), "\"")) 142 case zcncore.Success: 143 fmt.Println("Executed smart contract successfully with txn: ", t.scheme.GetTransactionHash()) 144 default: 145 msg := fmt.Sprint("\nExecute smart contract failed. Unknown status code: " + 146 strconv.Itoa(int(t.scheme.GetVerifyConfirmationStatus()))) 147 return errors.New(errCode, msg) 148 } 149 150 vo := new(verifyOutput) 151 if err := json.Unmarshal([]byte(t.scheme.GetVerifyOutput()), vo); err != nil { 152 return errors.New(errCode, "error while unmarshalling confirmation: "+err.Error()+", json: "+t.scheme.GetVerifyOutput()) 153 } 154 155 if vo.Confirmation.Transaction != nil { 156 t.Hash = vo.Confirmation.Transaction.GetHash() 157 t.TransactionOutput = vo.Confirmation.Transaction.GetTransactionOutput() 158 } else { 159 return errors.New(errCode, "got invalid confirmation (missing transaction)") 160 } 161 162 return nil 163 } 164 165 // GetSheme returns transaction scheme 166 func (t *transactionEntity) GetScheme() zcncore.TransactionScheme { 167 return t.scheme 168 } 169 170 // GetHash returns transaction hash 171 func (t *transactionEntity) GetHash() string { 172 return t.Hash 173 } 174 175 // SetHash sets transaction hash 176 func (t *transactionEntity) SetHash(hash string) { 177 t.Hash = hash 178 } 179 180 // GetTransactionOutput returns transaction output 181 func (t *transactionEntity) GetTransactionOutput() string { 182 return t.TransactionOutput 183 } 184 185 func (t *transactionEntity) GetCallback() TransactionCallbackAwaitable { 186 return t.callBack 187 } 188 189 // GetVersion returns transaction version 190 func (t *transactionEntity) GetVersion() string { 191 return t.Version 192 } 193 194 // Verify checks including of transaction in the blockchain. 195 func Verify(ctx context.Context, hash string) (Transaction, error) { 196 t, err := NewTransactionEntity(0) 197 if err != nil { 198 return nil, err 199 } 200 201 scheme := t.GetScheme() 202 203 if err := scheme.SetTransactionHash(hash); err != nil { 204 return nil, err 205 } 206 207 err = t.Verify(ctx) 208 209 return t, err 210 }