Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
afade4f
miner transaction request reduce timeout
storybehind Jul 5, 2025
03482a5
upload test
storybehind Jul 21, 2025
5699073
upload test
storybehind Jul 28, 2025
87e7ee7
Merge branch 'staging' into transcoder
storybehind Jul 28, 2025
44dec82
change func arg
storybehind Jul 28, 2025
19162fc
Merge branch 'transcoder' of https://github.com/0chain/gosdk into tra…
storybehind Jul 28, 2025
107c281
remove logs and reset miners
storybehind Aug 2, 2025
2d4071f
fix compilation
storybehind Aug 3, 2025
df4dbdf
client id support in zauth sign
storybehind Aug 19, 2025
a8fbe2e
add godocs
storybehind Sep 2, 2025
f1a2b7a
revert keystore.go same as staging
storybehind Sep 2, 2025
6d77040
Merge branch 'staging' into transcoder
storybehind Sep 2, 2025
6b1ddf5
fix compilation
storybehind Sep 2, 2025
34f7c5f
fix compilation
storybehind Sep 2, 2025
d497ed3
move method changes for multi wallet
goyalkunal151 Sep 27, 2025
d27ab0c
move method changes for multi wallet
goyalkunal151 Sep 27, 2025
7fb10ba
copy changes for multi wallet
goyalkunal151 Sep 27, 2025
a574e9f
add clientId for all operations
goyalkunal151 Sep 27, 2025
346ab97
make public key as key for wallet map
goyalkunal151 Sep 27, 2025
ea5f6a8
created SignByMultiWallet function
goyalkunal151 Oct 1, 2025
370243f
updated file operations and test files
goyalkunal151 Oct 1, 2025
2c22143
download
storybehind Oct 26, 2025
9e0ef1e
concurrency support
storybehind Oct 26, 2025
0bbf15d
use key
storybehind Oct 28, 2025
4b5ca7b
fix compilation
storybehind Oct 28, 2025
31f7236
fix compilation
storybehind Oct 28, 2025
7888d32
fix compilation
storybehind Oct 31, 2025
e66a8a6
init sdk
storybehind Oct 31, 2025
f959b3e
changes
storybehind Nov 2, 2025
ecae422
download test
storybehind Nov 6, 2025
246b9df
upload complete
storybehind Nov 7, 2025
be36134
Download Dir test
storybehind Nov 8, 2025
3b81f53
file operations and transaction signing
storybehind Nov 12, 2025
6720c71
changes in allocation file and add wasm functions
storybehind Nov 13, 2025
b4232ca
refactor
storybehind Nov 14, 2025
941f125
add logs
storybehind Nov 14, 2025
37dc8d8
upload fix
storybehind Nov 14, 2025
c2b500e
provide blobber multi-wallet operations wasm
storybehind Nov 16, 2025
2b190c2
allocation wasm functions
storybehind Nov 17, 2025
22ac139
player and add wallets wasm
storybehind Nov 17, 2025
73399fa
bridge mw wasm
storybehind Nov 18, 2025
c38fe9d
all wasm functions supported
storybehind Nov 18, 2025
565352f
fix
storybehind Nov 20, 2025
8f39d84
provide signing-key method
storybehind Nov 21, 2025
a9a9730
fix signing-key function
storybehind Nov 21, 2025
5269fe5
fix
storybehind Nov 24, 2025
40a2e22
fix wasm build
storybehind Dec 6, 2025
236a4b0
Merge branch 'staging' into multi-wallet-additional
storybehind Dec 7, 2025
7f59e3f
build fix
storybehind Dec 17, 2025
0b03965
fix mobile build
storybehind Dec 17, 2025
08c95fe
feat: dual-index wallets by ClientID and PublicKey to fix multi-walle…
nahom4 Jan 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
516 changes: 375 additions & 141 deletions core/client/set.go

Large diffs are not rendered by default.

20 changes: 18 additions & 2 deletions core/client/zauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -535,14 +535,22 @@ func CallZvaultRetrieveSharedWallets(serverAddr, token string) (string, error) {

// ZauthSignTxn returns a function that sends a txn signing request to the zauth server
func ZauthSignTxn(serverAddr string) sys.AuthorizeFunc {
return func(msg string) (string, error) {
return func(msg string, keys ...string) (string, error) {
req, err := http.NewRequest("POST", serverAddr+"/sign/txn", bytes.NewBuffer([]byte(msg)))
if err != nil {
return "", errors.Wrap(err, "failed to create HTTP request")
}
req.Header.Set("Content-Type", "application/json")
c := GetClient()
pubkey := c.Keys[0].PublicKey
if len(keys) > 0 {
c = GetWalletByKey(keys[0])
if c == nil {
return "", errors.Errorf("wallet not found for pubkey: %s", keys[0])
}
pubkey = c.Keys[0].PublicKey
}

req.Header.Set("X-Peer-Public-Key", pubkey)

client := &http.Client{}
Expand Down Expand Up @@ -572,14 +580,22 @@ func ZauthSignTxn(serverAddr string) sys.AuthorizeFunc {
}

func ZauthAuthCommon(serverAddr string) sys.AuthorizeFunc {
return func(msg string) (string, error) {
return func(msg string, keys ...string) (string, error) {
req, err := http.NewRequest("POST", serverAddr+"/sign/msg", bytes.NewBuffer([]byte(msg)))
if err != nil {
return "", errors.Wrap(err, "failed to create HTTP request")
}

c := GetClient()
pubkey := c.Keys[0].PublicKey
if len(keys) > 0 {
c = GetWalletByKey(keys[0])
if c == nil {
return "", errors.Errorf("multi-wallet-settings err: %v", keys[0])
}
pubkey = c.Keys[0].PublicKey
}

req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Peer-Public-Key", pubkey)

Expand Down
5 changes: 4 additions & 1 deletion core/sys/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ type KeyPair struct {
// SignFunc sign method for request verification
type SignFunc func(hash string, signatureScheme string, keys []KeyPair) (string, error)

// SignFunc sign method for request verification
type SignWithAuthFunc func(hash string, signatureScheme string, keys []KeyPair, pubkeys ...string) (string, error)

type VerifyFunc func(signature string, msg string) (bool, error)

type VerifyWithFunc func(pk, signature string, msg string) (bool, error)

type AuthorizeFunc func(msg string) (string, error)
type AuthorizeFunc func(msg string, pubkeys... string) (string, error)
2 changes: 1 addition & 1 deletion core/sys/vars.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ var (

// Sign sign method. it should be initialized on different platform.
Sign SignFunc
SignWithAuth SignFunc
SignWithAuth SignWithAuthFunc

// Verify verify method. it should be initialized on different platform.
Verify VerifyFunc
Expand Down
58 changes: 40 additions & 18 deletions core/transaction/entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ const (
FEES_TABLE = `/v1/fees_table`
)

type SignFunc = func(msg string) (string, error)
type SignFunc = func(msg string, keys ...string) (string, error)
type VerifyFunc = func(publicKey, signature, msgHash string) (bool, error)
type SignWithWallet = func(msg string, wallet interface{}) (string, error)

Expand Down Expand Up @@ -211,6 +211,14 @@ func (t *Transaction) getAuthorize() (string, error) {
return "", errors.New("not_initialized", "no authorize func is set, define it in native code and set in sys")
}

if t.MultiWalletSupportKey != "" {
authorize, err := sys.Authorize(string(jsonByte), t.MultiWalletSupportKey)
if err != nil {
return "", err
}
return authorize, nil
}

authorize, err := sys.Authorize(string(jsonByte))
if err != nil {
return "", err
Expand All @@ -222,7 +230,7 @@ func (t *Transaction) getAuthorize() (string, error) {
func (t *Transaction) ComputeHashAndSign(signHandler SignFunc) error {
t.ComputeHashData()
var err error
t.Signature, err = signHandler(t.Hash)
t.Signature, err = signHandler(t.Hash, t.MultiWalletSupportKey)
if err != nil {
return err
}
Expand Down Expand Up @@ -270,7 +278,7 @@ func (t *Transaction) VerifySigWith(pubkey string, verifyHandler VerifyFunc) (bo
}

func SendTransactionSync(txn *Transaction, miners []string) error {
const requestTimeout = 3 * time.Second // Timeout for each request
const requestTimeout = 12 * time.Second // Timeout for each request

fails := make(chan error, len(miners))
var wg sync.WaitGroup
Expand All @@ -282,7 +290,7 @@ func SendTransactionSync(txn *Transaction, miners []string) error {
go func(url string) {
defer wg.Done()

// Create a context with a 30-second timeout for each request
// Create a context with a 12-second timeout for each request
ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)
defer cancel()

Expand Down Expand Up @@ -320,6 +328,13 @@ func SendTransactionSync(txn *Transaction, miners []string) error {
}
}

// Reset stable miners list if any miner failed
if failureCount > 0 {
if nodeClient, err := client.GetNode(); err == nil {
nodeClient.ResetStableMiners()
}
}

if failureCount == len(miners) {
return fmt.Errorf(dominantErr)
}
Expand Down Expand Up @@ -523,22 +538,21 @@ func SmartContractTxnValue(scAddress string, sn SmartContractTxnData, value uint
}

func SmartContractTxnValueFeeWithRetry(scAddress string, sn SmartContractTxnData,
value, fee uint64, verifyTxn bool, clients ...string) (hash, out string, nonce int64, t *Transaction, err error) {
hash, out, nonce, t, err = SmartContractTxnValueFee(scAddress, sn, value, fee, verifyTxn, clients...)
value, fee uint64, verifyTxn bool, keys ...string) (hash, out string, nonce int64, t *Transaction, err error) {
hash, out, nonce, t, err = SmartContractTxnValueFee(scAddress, sn, value, fee, verifyTxn, keys...)

if err != nil && (strings.Contains(err.Error(), "invalid transaction nonce") || strings.Contains(err.Error(), "invalid future transaction")) {
return SmartContractTxnValueFee(scAddress, sn, value, fee, verifyTxn, clients...)
return SmartContractTxnValueFee(scAddress, sn, value, fee, verifyTxn, keys...)
}
return
}

func SmartContractTxnValueFee(scAddress string, sn SmartContractTxnData,
value, fee uint64, verifyTxn bool, clients ...string) (hash, out string, nonce int64, t *Transaction, err error) {
value, fee uint64, verifyTxn bool, keys ...string) (hash, out string, nonce int64, t *Transaction, err error) {

clientId := client.Id()
if len(clients) > 0 && clients[0] != "" {
clientId = clients[0]
}
// Determine client identifier/public key to use for signing. If an explicit key is
// provided in keys varargs, prefer it; otherwise default to SDK client id.
clientId := client.Id(keys...)

var requestBytes []byte
if requestBytes, err = json.Marshal(sn); err != nil {
Expand All @@ -555,8 +569,8 @@ func SmartContractTxnValueFee(scAddress string, sn SmartContractTxnData,
return
}

txn := NewTransactionEntity(client.Id(clientId),
cfg.ChainID, client.PublicKey(clientId), nonce)
txn := NewTransactionEntity(clientId,
cfg.ChainID, client.PublicKey(keys...), nonce)

txn.TransactionData = string(requestBytes)
txn.ToClientID = scAddress
Expand All @@ -565,8 +579,8 @@ func SmartContractTxnValueFee(scAddress string, sn SmartContractTxnData,
txn.TransactionType = TxnTypeSmartContract
txn.ClientID = clientId

if len(clients) > 1 {
txn.ToClientID = clients[1]
if len(keys) > 1 {
txn.ToClientID = keys[1]
txn.TransactionType = TxnTypeSend
}

Expand All @@ -586,12 +600,20 @@ func SmartContractTxnValueFee(scAddress string, sn SmartContractTxnData,
txn.TransactionNonce = client.Cache.GetNextNonce(txn.ClientID)
}

if len(keys) > 0 && keys[0] != "" {
txn.MultiWalletSupportKey = keys[0]
}

err = txn.ComputeHashAndSign(client.SignFn)
if err != nil {
return
}

if client.GetClient().IsSplit {

isSplit, err := client.IsWalletSplit(keys...)
if err != nil {
return
}
if isSplit {
txn.Signature, err = txn.getAuthorize()
if err != nil {
return
Expand Down
37 changes: 21 additions & 16 deletions core/transaction/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,25 @@ 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"`
Hash string `json:"hash,omitempty"`
Version string `json:"version,omitempty"`
ClientID string `json:"client_id,omitempty"`
PublicKey string `json:"public_key,omitempty"`
// MultiWalletSupportKey is set when the transaction needs external
// authorization (split-key wallets). It is embedded in the marshaled
// transaction so the external authorizer (sys.Authorize) can know which
// public key the signature should be associated with.
MultiWalletSupportKey string `json:"authorizer_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"`
}
27 changes: 18 additions & 9 deletions core/util/httpnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,18 +85,27 @@ func init() {

func httpDo(req *http.Request, ctx context.Context, cncl context.CancelFunc, f func(*http.Response, error) error) error {
c := make(chan error, 1)
done := make(chan struct{})

go func() { c <- f(Client.Do(req.WithContext(ctx))) }()
go func() {
select {
case c <- f(Client.Do(req.WithContext(ctx))):
// normal completion
case <-done:
// context cancelled, do not call f
}
}()

select {
case <-ctx.Done():
// Use the cancel function only after trying to get the result.
<-c // Wait for f to return.
return ctx.Err()
case err := <-c:
// Ensure that we call cncl after we are done with the response
defer cncl() // Move this here to ensure we cancel after processing
return err
case <-ctx.Done():
// Use the cancel function only after trying to get the result.
close(done)
cncl()
return ctx.Err()
case err := <-c:
// Ensure that we call cncl after we are done with the response
defer cncl() // Move this here to ensure we cancel after processing
return err
}
}

Expand Down
3 changes: 2 additions & 1 deletion core/version/version.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

//====== THIS IS AUTOGENERATED FILE. DO NOT MODIFY ========

package version
const VERSIONSTR = "v1.20.6-1-gafade4fb"

const VERSIONSTR = "v1.17.11-269-g7fd90660"
2 changes: 1 addition & 1 deletion core/zcncrypto/bls0chain_wasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

var (
Sign func(hash string) (string, error)
Sign func(hash string, keys ...string) (string, error)
)

// WasmScheme - a signature scheme for BLS0Chain Signature
Expand Down
5 changes: 4 additions & 1 deletion mobilesdk/sdk/sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,5 +508,8 @@ func decodeTicket(ticket string) (string, string, uint64, error) {
// }
// }
func RegisterAuthorizer(auth Autorizer) {
sys.Authorize = auth.Auth
sys.Authorize = func(msg string, clientIDs ...string) (string, error) {
// clientIDs are ignored as the interface only accepts msg
return auth.Auth(msg)
}
}
Loading
Loading