Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 20 additions & 0 deletions .github/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
changelog:
exclude:
labels:
- Skip-Release-Notes
categories:
- title: Bugfixes
labels:
- Bug-Fix
- title: New Features
labels:
- New Feature
- title: Enhancements
labels:
- Enhancement
- title: Not Yet Enabled
labels:
- Not-Yet-Enabled
- title: Other
labels:
- "*"
24 changes: 24 additions & 0 deletions .github/workflows/pr-type-category.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Check PR category and type
on:
pull_request:
branches:
- develop
types: [opened, synchronize, reopened, labeled, unlabeled, edited]
jobs:
check_label:
runs-on: ubuntu-latest
name: Check PR Category and Type
steps:
- name: Checking for correct number of required github pr labels
uses: mheap/github-action-required-labels@v2
with:
mode: exactly
count: 1
labels: "New Feature, Enhancement, Bug-Fix, Not-Yet-Enabled, Skip-Release-Notes"

- name: "Checking for PR Category in PR title. Should be like '<category>: <pr title>'."
run: |
if [[ ! "${{ github.event.pull_request.title }}" =~ ^.{2,}\:.{2,} ]]; then
echo "## PR Category is missing from PR title. Please add it like '<category>: <pr title>'." >> GITHUB_STEP_SUMMARY
exit 1
fi
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
# 1.18.0

## What's Changed

### New Features
* Dev Tools: Source map decoder by @barnjamin in https://github.com/algorand/go-algorand-sdk/pull/335

### Enhancements
* Github-Actions: Adding pr title and label checks by @algojack in https://github.com/algorand/go-algorand-sdk/pull/336

**Full Changelog**: https://github.com/algorand/go-algorand-sdk/compare/v1.17.0...v1.18.0


# 1.17.0

## What's Changed
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ test:

unit:
go test $(TEST_SOURCES_NO_CUCUMBER)
cd test && go test -timeout 0s --godog.strict=true --godog.format=pretty --godog.tags="@unit.offline,@unit.algod,@unit.indexer,@unit.transactions.keyreg,@unit.rekey,@unit.tealsign,@unit.dryrun,@unit.responses,@unit.applications,@unit.transactions,@unit.indexer.rekey,@unit.responses.messagepack,@unit.responses.231,@unit.responses.messagepack.231,@unit.responses.genesis,@unit.feetest,@unit.indexer.logs,@unit.abijson,@unit.abijson.byname,@unit.transactions.payment,@unit.atomic_transaction_composer,@unit.responses.unlimited_assets,@unit.indexer.ledger_refactoring,@unit.algod.ledger_refactoring,@unit.dryrun.trace.application" --test.v .
cd test && go test -timeout 0s --godog.strict=true --godog.format=pretty --godog.tags="@unit.sourcemap,@unit.offline,@unit.algod,@unit.indexer,@unit.transactions.keyreg,@unit.rekey,@unit.tealsign,@unit.dryrun,@unit.responses,@unit.applications,@unit.transactions,@unit.indexer.rekey,@unit.responses.messagepack,@unit.responses.231,@unit.responses.messagepack.231,@unit.responses.genesis,@unit.feetest,@unit.indexer.logs,@unit.abijson,@unit.abijson.byname,@unit.transactions.payment,@unit.atomic_transaction_composer,@unit.responses.unlimited_assets,@unit.indexer.ledger_refactoring,@unit.algod.ledger_refactoring,@unit.dryrun.trace.application" --test.v .

integration:
go test $(TEST_SOURCES_NO_CUCUMBER)
cd test && go test -timeout 0s --godog.strict=true --godog.format=pretty --godog.tags="@algod,@assets,@auction,@kmd,@send,@indexer,@rekey,@send.keyregtxn,@dryrun,@compile,@applications.verified,@indexer.applications,@indexer.231,@abi,@c2c" --test.v .
cd test && go test -timeout 0s --godog.strict=true --godog.format=pretty --godog.tags="@algod,@assets,@auction,@kmd,@send,@indexer,@rekey,@send.keyregtxn,@dryrun,@compile,@applications.verified,@indexer.applications,@indexer.231,@abi,@c2c,@compile.sourcemap" --test.v .

docker-test:
./test/docker/run_docker.sh
Expand Down
4 changes: 2 additions & 2 deletions client/v2/algod/algod.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ func (c *Client) getRaw(ctx context.Context, path string, body interface{}, head
// post sends a POST request to the given path with the given request object.
// No query parameters will be sent if request is nil.
// response must be a pointer to an object as post writes the response there.
func (c *Client) post(ctx context.Context, response interface{}, path string, body interface{}, headers []*common.Header) error {
return (*common.Client)(c).Post(ctx, response, path, body, headers)
func (c *Client) post(ctx context.Context, response interface{}, path string, params interface{}, headers []*common.Header, body interface{}) error {
return (*common.Client)(c).Post(ctx, response, path, params, headers, body)
}

// MakeClient is the factory for constructing a ClientV2 for a given endpoint.
Expand Down
3 changes: 1 addition & 2 deletions client/v2/algod/dryrun.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ func (s *TealDryRun) Do(
ctx context.Context,
headers ...*common.Header,
) (response models.DryrunResponse, err error) {
err = s.c.post(ctx, &response,
"/v2/teal/dryrun", s.rawobj, headers)
err = s.c.post(ctx, &response, "/v2/teal/dryrun", nil, headers, s.rawobj)
return
}
2 changes: 1 addition & 1 deletion client/v2/algod/rawTransaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func (s *SendRawTransaction) Do(ctx context.Context, headers ...*common.Header)
if addContentType {
headers = append(headers, &common.Header{"Content-Type", "application/x-binary"})
}
err = s.c.post(ctx, &response, "/v2/transactions", s.rawtxn, headers)
err = s.c.post(ctx, &response, "/v2/transactions", nil, headers, s.rawtxn)
txid = response.Txid
return
}
2 changes: 1 addition & 1 deletion client/v2/algod/tealCompile.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ func (s *TealCompile) Sourcemap(Sourcemap bool) *TealCompile {

// Do performs the HTTP request
func (s *TealCompile) Do(ctx context.Context, headers ...*common.Header) (response models.CompileResponse, err error) {
err = s.c.post(ctx, &response, "/v2/teal/compile", s.source, headers)
err = s.c.post(ctx, &response, "/v2/teal/compile", s.p, headers, s.source)
return
}
2 changes: 1 addition & 1 deletion client/v2/algod/tealDryrun.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ type TealDryrun struct {

// Do performs the HTTP request
func (s *TealDryrun) Do(ctx context.Context, headers ...*common.Header) (response models.DryrunResponse, err error) {
err = s.c.post(ctx, &response, "/v2/teal/dryrun", msgpack.Encode(&s.request), headers)
err = s.c.post(ctx, &response, "/v2/teal/dryrun", nil, headers, msgpack.Encode(&s.request))
return
}
59 changes: 30 additions & 29 deletions client/v2/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,33 +103,34 @@ func mergeRawQueries(q1, q2 string) string {
}

// submitFormRaw is a helper used for submitting (ex.) GETs and POSTs to the server
func (client *Client) submitFormRaw(ctx context.Context, path string, body interface{}, requestMethod string, encodeJSON bool, headers []*Header) (resp *http.Response, err error) {
func (client *Client) submitFormRaw(ctx context.Context, path string, params interface{}, requestMethod string, encodeJSON bool, headers []*Header, body interface{}) (resp *http.Response, err error) {
queryURL := client.serverURL
queryURL.Path += path

var req *http.Request
var bodyReader io.Reader
if body != nil {
if requestMethod == "POST" && rawRequestPaths[path] {
reqBytes, ok := body.([]byte)
if !ok {
return nil, fmt.Errorf("couldn't decode raw body as bytes")
}
bodyReader = bytes.NewBuffer(reqBytes)
} else {
v, err := query.Values(body)
if err != nil {
return nil, err
}

queryURL.RawQuery = mergeRawQueries(queryURL.RawQuery, v.Encode())
if encodeJSON {
jsonValue := json.Encode(body)
bodyReader = bytes.NewBuffer(jsonValue)
}
var v url.Values

if params != nil {
v, err = query.Values(params)
if err != nil {
return nil, err
}
}

if requestMethod == "POST" && rawRequestPaths[path] {
reqBytes, ok := body.([]byte)
if !ok {
return nil, fmt.Errorf("couldn't decode raw body as bytes")
}
bodyReader = bytes.NewBuffer(reqBytes)
} else if encodeJSON {
jsonValue := json.Encode(params)
bodyReader = bytes.NewBuffer(jsonValue)
}

queryURL.RawQuery = mergeRawQueries(queryURL.RawQuery, v.Encode())

req, err = http.NewRequest(requestMethod, queryURL.String(), bodyReader)
if err != nil {
return nil, err
Expand Down Expand Up @@ -161,8 +162,8 @@ func (client *Client) submitFormRaw(ctx context.Context, path string, body inter
return resp, nil
}

func (client *Client) submitForm(ctx context.Context, response interface{}, path string, body interface{}, requestMethod string, encodeJSON bool, headers []*Header) error {
resp, err := client.submitFormRaw(ctx, path, body, requestMethod, encodeJSON, headers)
func (client *Client) submitForm(ctx context.Context, response interface{}, path string, params interface{}, requestMethod string, encodeJSON bool, headers []*Header, body interface{}) error {
resp, err := client.submitFormRaw(ctx, path, params, requestMethod, encodeJSON, headers, body)
if err != nil {
return err
}
Expand Down Expand Up @@ -192,14 +193,14 @@ func (client *Client) submitForm(ctx context.Context, response interface{}, path
}

// Get performs a GET request to the specific path against the server
func (client *Client) Get(ctx context.Context, response interface{}, path string, body interface{}, headers []*Header) error {
return client.submitForm(ctx, response, path, body, "GET", false /* encodeJSON */, headers)
func (client *Client) Get(ctx context.Context, response interface{}, path string, params interface{}, headers []*Header) error {
return client.submitForm(ctx, response, path, params, "GET", false /* encodeJSON */, headers, nil)
}

// GetRaw performs a GET request to the specific path against the server and returns the raw body bytes.
func (client *Client) GetRaw(ctx context.Context, path string, body interface{}, headers []*Header) (response []byte, err error) {
func (client *Client) GetRaw(ctx context.Context, path string, params interface{}, headers []*Header) (response []byte, err error) {
var resp *http.Response
resp, err = client.submitFormRaw(ctx, path, body, "GET", false /* encodeJSON */, headers)
resp, err = client.submitFormRaw(ctx, path, params, "GET", false /* encodeJSON */, headers, nil)
if err != nil {
return nil, err
}
Expand All @@ -213,8 +214,8 @@ func (client *Client) GetRaw(ctx context.Context, path string, body interface{},
}

// GetRawMsgpack performs a GET request to the specific path against the server and returns the decoded messagepack response.
func (client *Client) GetRawMsgpack(ctx context.Context, response interface{}, path string, body interface{}, headers []*Header) error {
resp, err := client.submitFormRaw(ctx, path, body, "GET", false /* encodeJSON */, headers)
func (client *Client) GetRawMsgpack(ctx context.Context, response interface{}, path string, params interface{}, headers []*Header) error {
resp, err := client.submitFormRaw(ctx, path, params, "GET", false /* encodeJSON */, headers, nil)
if err != nil {
return err
}
Expand All @@ -238,8 +239,8 @@ func (client *Client) GetRawMsgpack(ctx context.Context, response interface{}, p
// Post sends a POST request to the given path with the given body object.
// No query parameters will be sent if body is nil.
// response must be a pointer to an object as post writes the response there.
func (client *Client) Post(ctx context.Context, response interface{}, path string, body interface{}, headers []*Header) error {
return client.submitForm(ctx, response, path, body, "POST", true /* encodeJSON */, headers)
func (client *Client) Post(ctx context.Context, response interface{}, path string, params interface{}, headers []*Header, body interface{}) error {
return client.submitForm(ctx, response, path, params, "POST", true /* encodeJSON */, headers, body)
}

// Helper function for correctly formatting and escaping URL path parameters.
Expand Down
4 changes: 2 additions & 2 deletions client/v2/indexer/indexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ func (c *Client) getRaw(ctx context.Context, path string, body interface{}, head
// post sends a POST request to the given path with the given request object.
// No query parameters will be sent if request is nil.
// response must be a pointer to an object as post writes the response there.
func (c *Client) post(ctx context.Context, response interface{}, path string, body interface{}, headers []*common.Header) error {
return (*common.Client)(c).Post(ctx, response, path, body, headers)
func (c *Client) post(ctx context.Context, response interface{}, path string, params interface{}, headers []*common.Header, body interface{}) error {
return (*common.Client)(c).Post(ctx, response, path, params, headers, body)
}

// MakeClient is the factory for constructing a ClientV2 for a given endpoint.
Expand Down
133 changes: 133 additions & 0 deletions logic/source_map.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package logic

import (
"fmt"
"strings"
)

// SourceMap provides a mapping of the source to assembled program
type SourceMap struct {
Version int `json:"version"`
File string `json:"file,omitempty"`
SourceRoot string `json:"sourceRoot,omitempty"`
Sources []string `json:"sources"`
Names []string `json:"names"`
Mappings string `json:"mappings"`
// Decoded mapping results
LineToPc map[int][]int
PcToLine map[int]int
}

func DecodeSourceMap(ism map[string]interface{}) (SourceMap, error) {
sm := SourceMap{}

if v, ok := ism["version"]; ok {
sm.Version = int(v.(float64))
}

if sm.Version != 3 {
return sm, fmt.Errorf("only version 3 is supported")
}

if f, ok := ism["file"]; ok {
sm.File = f.(string)
}

if sr, ok := ism["sourceRoot"]; ok {
sm.SourceRoot = sr.(string)
}

if srcs, ok := ism["sources"]; ok {
srcSlice := srcs.([]interface{})
sm.Sources = make([]string, len(srcSlice))
for idx, s := range srcSlice {
sm.Sources[idx] = s.(string)
}
}

if names, ok := ism["names"]; ok {
nameSlice := names.([]interface{})
sm.Names = make([]string, len(nameSlice))
for idx, n := range nameSlice {
sm.Names[idx] = n.(string)
}
}

if m, ok := ism["mappings"]; ok {
sm.Mappings = m.(string)
}

if sm.Mappings == "" {
return sm, fmt.Errorf("no mappings defined")
}

sm.PcToLine = map[int]int{}
sm.LineToPc = map[int][]int{}

lastLine := 0
for idx, chunk := range strings.Split(sm.Mappings, ";") {
vals := decodeSourceMapLine(chunk)
// If the vals length >= 3 the lineDelta
if len(vals) >= 3 {
lastLine = lastLine + vals[2] // Add the line delta
}

if _, ok := sm.LineToPc[lastLine]; !ok {
sm.LineToPc[lastLine] = []int{}
}

sm.LineToPc[lastLine] = append(sm.LineToPc[lastLine], idx)
sm.PcToLine[idx] = lastLine
}

return sm, nil
}

func (s *SourceMap) GetLineForPc(pc int) (int, bool) {
line, ok := s.PcToLine[pc]
return line, ok
}

func (s *SourceMap) GetPcsForLine(line int) []int {
return s.LineToPc[line]
}

const (
// consts used for vlq encoding/decoding
b64table string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
vlqShiftSize = 5
vlqFlag = 1 << vlqShiftSize
vlqMask = vlqFlag - 1
)

func decodeSourceMapLine(vlq string) []int {

var (
results []int
value, shift int
)

for i := 0; i < len(vlq); i++ {
digit := strings.Index(b64table, string(vlq[i]))

value |= (digit & int(vlqMask)) << shift

if digit&vlqFlag > 0 {
shift += vlqShiftSize
continue
}

if value&1 > 0 {
value = (value >> 1) * -1
} else {
value = value >> 1
}

results = append(results, value)

// Reset
value, shift = 0, 0
}

return results
}
1 change: 1 addition & 0 deletions test/algodclientv2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ func AlgodClientV2Context(s *godog.Suite) {
s.Step(`^we make an Account Information call against account "([^"]*)" with exclude "([^"]*)"$`, weMakeAnAccountInformationCallAgainstAccountWithExclude)
s.Step(`^we make an Account Asset Information call against account "([^"]*)" assetID (\d+)$`, weMakeAnAccountAssetInformationCallAgainstAccountAssetID)
s.Step(`^we make an Account Application Information call against account "([^"]*)" applicationID (\d+)$`, weMakeAnAccountApplicationInformationCallAgainstAccountApplicationID)

s.BeforeScenario(func(interface{}) {
globalErrForExamination = nil
})
Expand Down
Loading