-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1672 from 0chain/sprint-1.18
Sprint 1.18
- Loading branch information
Showing
255 changed files
with
5,778 additions
and
21,007 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package constants | ||
|
||
type SignScheme string | ||
|
||
const ( | ||
ED25519 SignScheme = "ed25519" | ||
BLS0CHAIN SignScheme = "bls0chain" | ||
) | ||
|
||
func (s SignScheme) String() string { | ||
return string(s) | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
package client | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"github.com/0chain/errors" | ||
"github.com/0chain/gosdk/core/conf" | ||
"github.com/0chain/gosdk/core/util" | ||
"github.com/shopspring/decimal" | ||
"log" | ||
"net/http" | ||
"net/url" | ||
"sync" | ||
) | ||
|
||
// SCRestAPIHandler is a function type to handle the response from the SC Rest API | ||
// | ||
// `response` - the response from the SC Rest API | ||
// `numSharders` - the number of sharders that responded | ||
// `err` - the error if any | ||
type SCRestAPIHandler func(response map[string][]byte, numSharders int, err error) | ||
|
||
func MakeSCRestAPICall(scAddress string, relativePath string, params map[string]string, restApiUrls ...string) ([]byte, error) { | ||
const ( | ||
consensusThresh = float32(25.0) | ||
ScRestApiUrl = "v1/screst/" | ||
) | ||
|
||
restApiUrl := ScRestApiUrl | ||
if len(restApiUrls) > 0 { | ||
restApiUrl = restApiUrls[0] | ||
} | ||
|
||
sharders := nodeClient.sharders.Healthy() | ||
responses := make(map[int]int) | ||
entityResult := make(map[string][]byte) | ||
|
||
var ( | ||
retObj []byte | ||
maxCount int | ||
dominant = 200 | ||
wg sync.WaitGroup | ||
mu sync.Mutex // Mutex to protect shared resources | ||
) | ||
|
||
cfg, err := conf.GetClientConfig() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
for _, sharder := range sharders { | ||
wg.Add(1) | ||
go func(sharder string) { | ||
defer wg.Done() | ||
|
||
urlString := fmt.Sprintf("%v/%v%v%v", sharder, restApiUrl, scAddress, relativePath) | ||
urlObj, err := url.Parse(urlString) | ||
if err != nil { | ||
log.Println(err.Error()) | ||
return | ||
} | ||
q := urlObj.Query() | ||
for k, v := range params { | ||
q.Add(k, v) | ||
} | ||
urlObj.RawQuery = q.Encode() | ||
|
||
req, err := util.NewHTTPGetRequest(urlObj.String()) | ||
if err != nil { | ||
log.Println("Error creating request", err.Error()) | ||
return | ||
} | ||
|
||
response, err := req.Get() | ||
if err != nil { | ||
nodeClient.sharders.Fail(sharder) | ||
log.Println("Error getting response", err.Error()) | ||
return | ||
} | ||
|
||
mu.Lock() // Lock before updating shared maps | ||
defer mu.Unlock() | ||
|
||
if response.StatusCode > http.StatusBadRequest { | ||
nodeClient.sharders.Fail(sharder) | ||
} else { | ||
nodeClient.sharders.Success(sharder) | ||
} | ||
|
||
responses[response.StatusCode]++ | ||
if responses[response.StatusCode] > maxCount { | ||
maxCount = responses[response.StatusCode] | ||
} | ||
|
||
if isCurrentDominantStatus(response.StatusCode, responses, maxCount) { | ||
dominant = response.StatusCode | ||
retObj = []byte(response.Body) | ||
} | ||
|
||
entityResult[sharder] = []byte(response.Body) | ||
nodeClient.sharders.Success(sharder) | ||
}(sharder) | ||
} | ||
|
||
wg.Wait() | ||
|
||
rate := float32(maxCount*100) / float32(cfg.SharderConsensous) | ||
if rate < consensusThresh { | ||
err = errors.New("consensus_failed", "consensus failed on sharders") | ||
} | ||
|
||
if dominant != 200 { | ||
var objmap map[string]json.RawMessage | ||
err := json.Unmarshal(retObj, &objmap) | ||
if err != nil { | ||
return nil, errors.New("", string(retObj)) | ||
} | ||
|
||
var parsed string | ||
err = json.Unmarshal(objmap["error"], &parsed) | ||
if err != nil || parsed == "" { | ||
return nil, errors.New("", string(retObj)) | ||
} | ||
|
||
return nil, errors.New("", parsed) | ||
} | ||
|
||
if rate > consensusThresh { | ||
return retObj, nil | ||
} | ||
return nil, err | ||
} | ||
|
||
// isCurrentDominantStatus determines whether the current response status is the dominant status among responses. | ||
// | ||
// The dominant status is where the response status is counted the most. | ||
// On tie-breakers, 200 will be selected if included. | ||
// | ||
// Function assumes runningTotalPerStatus can be accessed safely concurrently. | ||
func isCurrentDominantStatus(respStatus int, currentTotalPerStatus map[int]int, currentMax int) bool { | ||
// mark status as dominant if | ||
// - running total for status is the max and response is 200 or | ||
// - running total for status is the max and count for 200 is lower | ||
return currentTotalPerStatus[respStatus] == currentMax && (respStatus == 200 || currentTotalPerStatus[200] < currentMax) | ||
} | ||
|
||
func GetBalance(clientIDs ...string) (*GetBalanceResponse, error) { | ||
const GetBalance = "client/get/balance" | ||
var ( | ||
balance GetBalanceResponse | ||
err error | ||
res []byte | ||
) | ||
|
||
var clientID string | ||
if len(clientIDs) > 0 { | ||
clientID = clientIDs[0] | ||
} else { | ||
clientID = Id() | ||
} | ||
|
||
if res, err = MakeSCRestAPICall("", GetBalance, map[string]string{ | ||
"client_id": clientID, | ||
}, "v1/"); err != nil { | ||
return nil, err | ||
} | ||
|
||
if err = json.Unmarshal(res, &balance); err != nil { | ||
return nil, err | ||
} | ||
|
||
return &balance, nil | ||
} | ||
|
||
type GetBalanceResponse struct { | ||
Txn string `json:"txn"` | ||
Round int64 `json:"round"` | ||
Balance int64 `json:"balance"` | ||
Nonce int64 `json:"nonce"` | ||
} | ||
|
||
// ToToken converts Balance to ZCN tokens. | ||
func (b GetBalanceResponse) ToToken() (float64, error) { | ||
f, _ := decimal.New(b.Balance, -10).Float64() | ||
return f, nil | ||
} |
Oops, something went wrong.