diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5674a16c..6c07a5cd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ on: pull_request: env: - go_version: 1.18 + go_version: 1.19 GO111MODULE: on COVERALLS_TOKEN: ${{ secrets.COVERALLS_TOKEN }} @@ -57,15 +57,15 @@ jobs: - uses: actions/checkout@v3 with: version: latest - - run: make check-format - + - run: make check-format + Check-Gen: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 with: version: latest - - run: make check-gen + - run: make check-gen Coverage: runs-on: ubuntu-latest @@ -85,4 +85,3 @@ jobs: with: version: latest - run: make salus - \ No newline at end of file diff --git a/asserter/asserter.go b/asserter/asserter.go index fb5d0c28..0f3974a2 100644 --- a/asserter/asserter.go +++ b/asserter/asserter.go @@ -17,7 +17,7 @@ package asserter import ( "encoding/json" "fmt" - "io/ioutil" + "os" "path" "strings" @@ -240,7 +240,7 @@ type Configuration struct { func NewClientWithFile( filePath string, ) (*Asserter, error) { - content, err := ioutil.ReadFile(path.Clean(filePath)) + content, err := os.ReadFile(path.Clean(filePath)) if err != nil { return nil, fmt.Errorf("failed to read file %s: %w", filePath, err) } @@ -438,7 +438,7 @@ func getValidationConfig(validationFilePath string) (*Validations, error) { Enabled: false, } if validationFilePath != "" { - content, err := ioutil.ReadFile(path.Clean(validationFilePath)) + content, err := os.ReadFile(path.Clean(validationFilePath)) if err != nil { return nil, fmt.Errorf("failed to read file %s: %w", validationFilePath, err) } diff --git a/asserter/asserter_test.go b/asserter/asserter_test.go index 30df1389..ca850b71 100644 --- a/asserter/asserter_test.go +++ b/asserter/asserter_test.go @@ -18,7 +18,6 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" "os" "testing" @@ -410,7 +409,7 @@ func TestNew(t *testing.T) { fileConfig.AllowedTimestampStartIndex = fileConfig.GenesisBlockIdentifier.Index + 1 } - tmpfile, err := ioutil.TempFile("", "test.json") + tmpfile, err := os.CreateTemp("", "test.json") assert.NoError(t, err) defer os.Remove(tmpfile.Name()) @@ -473,7 +472,7 @@ func TestNew(t *testing.T) { }) t.Run("file not formatted correctly", func(t *testing.T) { - tmpfile, err := ioutil.TempFile("", "test.json") + tmpfile, err := os.CreateTemp("", "test.json") assert.NoError(t, err) defer os.Remove(tmpfile.Name()) @@ -515,7 +514,7 @@ func TestNew(t *testing.T) { }) t.Run("wrong format of validation file", func(t *testing.T) { - tmpfile, err := ioutil.TempFile("", "test.json") + tmpfile, err := os.CreateTemp("", "test.json") assert.NoError(t, err) defer os.Remove(tmpfile.Name()) diff --git a/client/api_account.go b/client/api_account.go index aa3dd5d1..9e4567e8 100644 --- a/client/api_account.go +++ b/client/api_account.go @@ -20,7 +20,6 @@ import ( _context "context" "fmt" "io" - _ioutil "io/ioutil" _nethttp "net/http" "github.com/coinbase/rosetta-sdk-go/types" @@ -87,7 +86,7 @@ func (a *AccountAPIService) AccountBalance( return nil, nil, fmt.Errorf("failed to call API: %w", err) } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) defer func() { _, _ = io.Copy(io.Discard, localVarHTTPResponse.Body) _ = localVarHTTPResponse.Body.Close() @@ -193,7 +192,7 @@ func (a *AccountAPIService) AccountCoins( return nil, nil, fmt.Errorf("failed to call API: %w", err) } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) defer func() { _, _ = io.Copy(io.Discard, localVarHTTPResponse.Body) _ = localVarHTTPResponse.Body.Close() diff --git a/client/api_block.go b/client/api_block.go index e9531245..cd12b8ce 100644 --- a/client/api_block.go +++ b/client/api_block.go @@ -20,7 +20,6 @@ import ( _context "context" "fmt" "io" - _ioutil "io/ioutil" _nethttp "net/http" "github.com/coinbase/rosetta-sdk-go/types" @@ -84,7 +83,7 @@ func (a *BlockAPIService) Block( return nil, nil, fmt.Errorf("failed to call API: %w", err) } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) defer func() { _, _ = io.Copy(io.Discard, localVarHTTPResponse.Body) _ = localVarHTTPResponse.Body.Close() @@ -193,7 +192,7 @@ func (a *BlockAPIService) BlockTransaction( return nil, nil, fmt.Errorf("failed to call API: %w", err) } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) defer func() { _, _ = io.Copy(io.Discard, localVarHTTPResponse.Body) _ = localVarHTTPResponse.Body.Close() diff --git a/client/api_call.go b/client/api_call.go index 27e4031f..1e1caa5e 100644 --- a/client/api_call.go +++ b/client/api_call.go @@ -20,7 +20,6 @@ import ( _context "context" "fmt" "io" - _ioutil "io/ioutil" _nethttp "net/http" "github.com/coinbase/rosetta-sdk-go/types" @@ -87,7 +86,7 @@ func (a *CallAPIService) Call( return nil, nil, fmt.Errorf("failed to call API: %w", err) } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) defer func() { _, _ = io.Copy(io.Discard, localVarHTTPResponse.Body) _ = localVarHTTPResponse.Body.Close() diff --git a/client/api_construction.go b/client/api_construction.go index e6a302f6..f4939874 100644 --- a/client/api_construction.go +++ b/client/api_construction.go @@ -20,7 +20,6 @@ import ( _context "context" "fmt" "io" - _ioutil "io/ioutil" _nethttp "net/http" "github.com/coinbase/rosetta-sdk-go/types" @@ -79,7 +78,7 @@ func (a *ConstructionAPIService) ConstructionCombine( return nil, nil, fmt.Errorf("failed to call API: %w", err) } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) defer func() { _, _ = io.Copy(io.Discard, localVarHTTPResponse.Body) _ = localVarHTTPResponse.Body.Close() @@ -176,7 +175,7 @@ func (a *ConstructionAPIService) ConstructionDerive( return nil, nil, fmt.Errorf("failed to call API: %w", err) } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) defer func() { _, _ = io.Copy(io.Discard, localVarHTTPResponse.Body) _ = localVarHTTPResponse.Body.Close() @@ -273,7 +272,7 @@ func (a *ConstructionAPIService) ConstructionHash( return nil, nil, fmt.Errorf("failed to call API: %w", err) } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) defer func() { _, _ = io.Copy(io.Discard, localVarHTTPResponse.Body) _ = localVarHTTPResponse.Body.Close() @@ -377,7 +376,7 @@ func (a *ConstructionAPIService) ConstructionMetadata( return nil, nil, fmt.Errorf("failed to call API: %w", err) } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) defer func() { _, _ = io.Copy(io.Discard, localVarHTTPResponse.Body) _ = localVarHTTPResponse.Body.Close() @@ -475,7 +474,7 @@ func (a *ConstructionAPIService) ConstructionParse( return nil, nil, fmt.Errorf("failed to call API: %w", err) } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) defer func() { _, _ = io.Copy(io.Discard, localVarHTTPResponse.Body) _ = localVarHTTPResponse.Body.Close() @@ -578,7 +577,7 @@ func (a *ConstructionAPIService) ConstructionPayloads( return nil, nil, fmt.Errorf("failed to call API: %w", err) } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) defer func() { _, _ = io.Copy(io.Discard, localVarHTTPResponse.Body) _ = localVarHTTPResponse.Body.Close() @@ -679,7 +678,7 @@ func (a *ConstructionAPIService) ConstructionPreprocess( return nil, nil, fmt.Errorf("failed to call API: %w", err) } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) defer func() { _, _ = io.Copy(io.Discard, localVarHTTPResponse.Body) _ = localVarHTTPResponse.Body.Close() @@ -779,7 +778,7 @@ func (a *ConstructionAPIService) ConstructionSubmit( return nil, nil, fmt.Errorf("failed to call API: %w", err) } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) defer func() { _, _ = io.Copy(io.Discard, localVarHTTPResponse.Body) _ = localVarHTTPResponse.Body.Close() diff --git a/client/api_events.go b/client/api_events.go index 15574350..e8ca8013 100644 --- a/client/api_events.go +++ b/client/api_events.go @@ -20,7 +20,6 @@ import ( _context "context" "fmt" "io" - _ioutil "io/ioutil" _nethttp "net/http" "github.com/coinbase/rosetta-sdk-go/types" @@ -82,7 +81,7 @@ func (a *EventsAPIService) EventsBlocks( return nil, nil, fmt.Errorf("failed to call API: %w", err) } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) defer func() { _, _ = io.Copy(io.Discard, localVarHTTPResponse.Body) _ = localVarHTTPResponse.Body.Close() diff --git a/client/api_mempool.go b/client/api_mempool.go index 1ed26900..e263505c 100644 --- a/client/api_mempool.go +++ b/client/api_mempool.go @@ -20,7 +20,6 @@ import ( _context "context" "fmt" "io" - _ioutil "io/ioutil" _nethttp "net/http" "github.com/coinbase/rosetta-sdk-go/types" @@ -77,7 +76,7 @@ func (a *MempoolAPIService) Mempool( return nil, nil, fmt.Errorf("failed to call API: %w", err) } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) defer func() { _, _ = io.Copy(io.Discard, localVarHTTPResponse.Body) _ = localVarHTTPResponse.Body.Close() @@ -179,7 +178,7 @@ func (a *MempoolAPIService) MempoolTransaction( return nil, nil, fmt.Errorf("failed to call API: %w", err) } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) defer func() { _, _ = io.Copy(io.Discard, localVarHTTPResponse.Body) _ = localVarHTTPResponse.Body.Close() diff --git a/client/api_network.go b/client/api_network.go index da2a52a9..ee15ec36 100644 --- a/client/api_network.go +++ b/client/api_network.go @@ -20,7 +20,6 @@ import ( _context "context" "fmt" "io" - _ioutil "io/ioutil" _nethttp "net/http" "github.com/coinbase/rosetta-sdk-go/types" @@ -77,7 +76,7 @@ func (a *NetworkAPIService) NetworkList( return nil, nil, fmt.Errorf("failed to call API: %w", err) } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) defer func() { _, _ = io.Copy(io.Discard, localVarHTTPResponse.Body) _ = localVarHTTPResponse.Body.Close() @@ -176,7 +175,7 @@ func (a *NetworkAPIService) NetworkOptions( return nil, nil, fmt.Errorf("failed to call API: %w", err) } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) defer func() { _, _ = io.Copy(io.Discard, localVarHTTPResponse.Body) _ = localVarHTTPResponse.Body.Close() @@ -273,7 +272,7 @@ func (a *NetworkAPIService) NetworkStatus( return nil, nil, fmt.Errorf("failed to call API: %w", err) } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) defer func() { _, _ = io.Copy(io.Discard, localVarHTTPResponse.Body) _ = localVarHTTPResponse.Body.Close() diff --git a/client/api_search.go b/client/api_search.go index 9f935f4d..3deb12f8 100644 --- a/client/api_search.go +++ b/client/api_search.go @@ -20,7 +20,6 @@ import ( _context "context" "fmt" "io" - _ioutil "io/ioutil" _nethttp "net/http" "github.com/coinbase/rosetta-sdk-go/types" @@ -82,7 +81,7 @@ func (a *SearchAPIService) SearchTransactions( return nil, nil, fmt.Errorf("failed to call API: %w", err) } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) defer func() { _, _ = io.Copy(io.Discard, localVarHTTPResponse.Body) _ = localVarHTTPResponse.Body.Close() diff --git a/codegen.sh b/codegen.sh index 098af412..d378c6a9 100755 --- a/codegen.sh +++ b/codegen.sh @@ -15,46 +15,43 @@ OS="$(uname)" case "${OS}" in - 'Linux') - OS='linux' - SED_IFLAG=(-i'') - ;; - 'Darwin') - OS='macos' - SED_IFLAG=(-i '') - ;; - *) - echo "Operating system '${OS}' not supported." - exit 1 - ;; +'Linux') + OS='linux' + SED_IFLAG=(-i'') + ;; +'Darwin') + OS='macos' + SED_IFLAG=(-i '') + ;; +*) + echo "Operating system '${OS}' not supported." + exit 1 + ;; esac # Remove existing client generated code -mkdir -p tmp; -DIRS=( types client server ) -IGNORED_FILES=( README.md utils.go utils_test.go marshal_test.go account_currency.go account_coin.go ) - -for dir in "${DIRS[@]}" -do - rm -rf tmp/*; - for file in "${IGNORED_FILES[@]}" - do - [ -f "${dir:?}"/"${file:?}" ] && mv "${dir:?}"/"${file:?}" tmp; +mkdir -p tmp +DIRS=(types client server) +IGNORED_FILES=(README.md utils.go utils_test.go marshal_test.go account_currency.go account_coin.go) + +for dir in "${DIRS[@]}"; do + rm -rf tmp/* + for file in "${IGNORED_FILES[@]}"; do + [ -f "${dir:?}"/"${file:?}" ] && mv "${dir:?}"/"${file:?}" tmp done - rm -rf "${dir:?}"/*; + rm -rf "${dir:?}"/* - for file in "${IGNORED_FILES[@]}" - do - [ -f tmp/"${file:?}" ] && mv tmp/"${file:?}" "${dir:?}"/"${file:?}"; + for file in "${IGNORED_FILES[@]}"; do + [ -f tmp/"${file:?}" ] && mv tmp/"${file:?}" "${dir:?}"/"${file:?}" done done -rm -rf tmp; +rm -rf tmp # Download spec file from releases ROSETTA_SPEC_VERSION=1.4.12 -curl -L https://github.com/coinbase/rosetta-specifications/releases/download/v${ROSETTA_SPEC_VERSION}/api.json -o api.json; +curl -L https://github.com/coinbase/rosetta-specifications/releases/download/v${ROSETTA_SPEC_VERSION}/api.json -o api.json # Generate client + types code GENERATOR_VERSION=v4.3.0 @@ -63,23 +60,22 @@ docker run --user "$(id -u):$(id -g)" --rm -v "${PWD}":/local \ -i /local/api.json \ -g go \ -t /local/templates/client \ - --additional-properties packageName=client\ - -o /local/client_tmp; + --additional-properties packageName=client -o /local/client_tmp # Remove unnecessary client files -rm -f client_tmp/go.mod; -rm -f client_tmp/README.md; -rm -f client_tmp/go.mod; -rm -f client_tmp/go.sum; -rm -rf client_tmp/api; -rm -rf client_tmp/docs; -rm -f client_tmp/git_push.sh; -rm -f client_tmp/.travis.yml; -rm -f client_tmp/.gitignore; -rm -f client_tmp/.openapi-generator-ignore; -rm -rf client_tmp/.openapi-generator; -mv client_tmp/* client; -rm -rf client_tmp; +rm -f client_tmp/go.mod +rm -f client_tmp/README.md +rm -f client_tmp/go.mod +rm -f client_tmp/go.sum +rm -rf client_tmp/api +rm -rf client_tmp/docs +rm -f client_tmp/git_push.sh +rm -f client_tmp/.travis.yml +rm -f client_tmp/.gitignore +rm -f client_tmp/.openapi-generator-ignore +rm -rf client_tmp/.openapi-generator +mv client_tmp/* client +rm -rf client_tmp # Add server code docker run --user "$(id -u):$(id -g)" --rm -v "${PWD}":/local \ @@ -87,127 +83,123 @@ docker run --user "$(id -u):$(id -g)" --rm -v "${PWD}":/local \ -i /local/api.json \ -g go-server \ -t /local/templates/server \ - --additional-properties packageName=server\ - -o /local/server_tmp; + --additional-properties packageName=server -o /local/server_tmp # Remove unnecessary server files -rm -rf server_tmp/api; -rm -rf server_tmp/.openapi-generator; -rm -f server_tmp/.openapi-generator-ignore; -rm -f server_tmp/go.mod; -rm -f server_tmp/main.go; -rm -f server_tmp/README.md; -rm -f server_tmp/Dockerfile; -mv server_tmp/go/* server_tmp/.; -rm -rf server_tmp/go; +rm -rf server_tmp/api +rm -rf server_tmp/.openapi-generator +rm -f server_tmp/.openapi-generator-ignore +rm -f server_tmp/go.mod +rm -f server_tmp/main.go +rm -f server_tmp/README.md +rm -f server_tmp/Dockerfile +mv server_tmp/go/* server_tmp/. +rm -rf server_tmp/go rm -f server_tmp/model_*.go rm -f server_tmp/*_service.go -mv server_tmp/* server; -rm -rf server_tmp; +mv server_tmp/* server +rm -rf server_tmp # Remove spec file -rm -f api.json; +rm -f api.json # Fix linting issues -sed "${SED_IFLAG[@]}" 's/Api/API/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/Json/JSON/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/Id /ID /g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/Url/URL/g' client/* server/*; +sed "${SED_IFLAG[@]}" 's/Api/API/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/Json/JSON/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/Id /ID /g' client/* server/* +sed "${SED_IFLAG[@]}" 's/Url/URL/g' client/* server/* # Fix enum pointers -sed "${SED_IFLAG[@]}" 's/*CurveType/CurveType/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/*SignatureType/SignatureType/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/*CoinAction/CoinAction/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/*ExemptionType/ExemptionType/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/*BlockEventType/BlockEventType/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/*Direction/Direction/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/*Case/Case/g' client/* server/*; +sed "${SED_IFLAG[@]}" 's/*CurveType/CurveType/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/*SignatureType/SignatureType/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/*CoinAction/CoinAction/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/*ExemptionType/ExemptionType/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/*BlockEventType/BlockEventType/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/*Direction/Direction/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/*Case/Case/g' client/* server/* # Fix CurveTypes, SignatureTypes, CoinActions, ExemptionTypes, Direction, Case -sed "${SED_IFLAG[@]}" 's/SECP256K1/Secp256k1/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/SECP256R1/Secp256r1/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/EDWARDS25519/Edwards25519/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/TWEEDLE/Tweedle/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/ECDSA_RECOVERY/EcdsaRecovery/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/ECDSA/Ecdsa/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/ED25519/Ed25519/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/SCHNORR_1/Schnorr1/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/SCHNORR_POSEIDON/SchnorrPoseidon/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/PALLAS/Pallas/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/CREATED/CoinCreated/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/SPENT/CoinSpent/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/GREATER_OR_EQUAL/BalanceGreaterOrEqual/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/LESS_OR_EQUAL/BalanceLessOrEqual/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/DYNAMIC/BalanceDynamic/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/FORWARD/Forward/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/BACKWARD/Backward/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/UPPER_CASE/UpperCase/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/LOWER_CASE/LowerCase/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/CASE_SENSITIVE/CaseSensitive/g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/NULL/Null/g' client/* server/*; +sed "${SED_IFLAG[@]}" 's/SECP256K1/Secp256k1/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/SECP256R1/Secp256r1/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/EDWARDS25519/Edwards25519/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/TWEEDLE/Tweedle/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/ECDSA_RECOVERY/EcdsaRecovery/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/ECDSA/Ecdsa/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/ED25519/Ed25519/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/SCHNORR_1/Schnorr1/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/SCHNORR_POSEIDON/SchnorrPoseidon/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/PALLAS/Pallas/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/CREATED/CoinCreated/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/SPENT/CoinSpent/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/GREATER_OR_EQUAL/BalanceGreaterOrEqual/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/LESS_OR_EQUAL/BalanceLessOrEqual/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/DYNAMIC/BalanceDynamic/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/FORWARD/Forward/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/BACKWARD/Backward/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/UPPER_CASE/UpperCase/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/LOWER_CASE/LowerCase/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/CASE_SENSITIVE/CaseSensitive/g' client/* server/* +sed "${SED_IFLAG[@]}" 's/NULL/Null/g' client/* server/* # Convert HexBytes to Bytes -sed "${SED_IFLAG[@]}" '/Hex-encoded public key bytes in the format specified by the CurveType/d' client/* server/*; -sed "${SED_IFLAG[@]}" -E 's/HexBytes[[:space:]]+string/Bytes []byte/g' client/* server/*; +sed "${SED_IFLAG[@]}" '/Hex-encoded public key bytes in the format specified by the CurveType/d' client/* server/* +sed "${SED_IFLAG[@]}" -E 's/HexBytes[[:space:]]+string/Bytes []byte/g' client/* server/* # Remove special characters -sed "${SED_IFLAG[@]}" 's/`//g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/\"//g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/\<b>//g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/\<\/b>//g' client/* server/*; -sed "${SED_IFLAG[@]}" 's///g' client/* server/*; -sed "${SED_IFLAG[@]}" 's/<\/code>//g' client/* server/*; +sed "${SED_IFLAG[@]}" 's/`//g' client/* server/* +sed "${SED_IFLAG[@]}" 's/\"//g' client/* server/* +sed "${SED_IFLAG[@]}" 's/\<b>//g' client/* server/* +sed "${SED_IFLAG[@]}" 's/\<\/b>//g' client/* server/* +sed "${SED_IFLAG[@]}" 's///g' client/* server/* +sed "${SED_IFLAG[@]}" 's/<\/code>//g' client/* server/* # Fix slice containing pointers -sed "${SED_IFLAG[@]}" 's/\*\[\]/\[\]\*/g' client/* server/*; +sed "${SED_IFLAG[@]}" 's/\*\[\]/\[\]\*/g' client/* server/* # Fix map pointers -sed "${SED_IFLAG[@]}" 's/\*map/map/g' client/* server/*; +sed "${SED_IFLAG[@]}" 's/\*map/map/g' client/* server/* # Fix string array pointers -sed "${SED_IFLAG[@]}" 's/\[\]\*string/\[\]string/g' client/* server/*; +sed "${SED_IFLAG[@]}" 's/\[\]\*string/\[\]string/g' client/* server/* # Move model files to types/ -mv client/model_*.go types/; +mv client/model_*.go types/ for file in types/model_*.go; do - mv "$file" "${file/model_/}" + mv "$file" "${file/model_/}" done # Change model files to correct package -sed "${SED_IFLAG[@]}" 's/package client/package types/g' types/*; +sed "${SED_IFLAG[@]}" 's/package client/package types/g' types/* # Add version file -VERSION_CONTENTS=$(sed "s/VERSION/${ROSETTA_SPEC_VERSION}/g" < templates/types.txt); -echo "${VERSION_CONTENTS}" >> "types/types.go"; - +VERSION_CONTENTS=$(sed "s/VERSION/${ROSETTA_SPEC_VERSION}/g" >"types/types.go" # Inject Custom Marshaling Logic # shellcheck disable=SC2013 -for file in $(grep -Ril "hex_bytes" types) -do - if [[ "${file}" == *"_test.go"* ]];then - echo "Skipping injection for ${file}"; - continue; +for file in $(grep -Ril "hex_bytes" types); do + if [[ "${file}" == *"_test.go"* ]]; then + echo "Skipping injection for ${file}" + continue fi - RAW_NAME=$(echo "${file}" | cut -c7- | rev | cut -c4- | rev); - STRUCT_NAME=$(echo "${RAW_NAME}" | perl -pe 's/(?:\b|_)(\p{Ll})/\u$1/g'); - MARSHAL_CONTENTS=$(sed "s/STRUCT_NAME/${STRUCT_NAME}/g" < templates/marshal.txt); - echo "${MARSHAL_CONTENTS}" >> "${file}"; + RAW_NAME=$(echo "${file}" | cut -c7- | rev | cut -c4- | rev) + STRUCT_NAME=$(echo "${RAW_NAME}" | perl -pe 's/(?:\b|_)(\p{Ll})/\u$1/g') + MARSHAL_CONTENTS=$(sed "s/STRUCT_NAME/${STRUCT_NAME}/g" >"${file}" # shellcheck disable=SC1004 sed "${SED_IFLAG[@]}" 's/package types/package types\ import \(\ \"encoding\/hex\"\ \"encoding\/json\"\ - \)/g' "${file}"; + \)/g' "${file}" done # Override certain types with complex marshaling -OVERRIDDEN_TYPES=( signing_payload construction_derive_response construction_parse_response ) -for type in "${OVERRIDDEN_TYPES[@]}" -do - echo "Overriding ${type}"; - rm "types/${type}.go" && cp "templates/${type}.txt" "types/${type}.go"; +OVERRIDDEN_TYPES=(signing_payload construction_derive_response construction_parse_response) +for type in "${OVERRIDDEN_TYPES[@]}"; do + echo "Overriding ${type}" + rm "types/${type}.go" && cp "templates/${type}.txt" "types/${type}.go" done cp "templates/go.mod.types" "types/go.mod" @@ -216,7 +208,7 @@ cd .. # Format client generated code FORMAT_GEN="gofmt -w /local/types; gofmt -w /local/client; gofmt -w /local/server" -GOLANG_VERSION=1.18 +GOLANG_VERSION=1.19 docker run --rm -v "${PWD}":/local \ golang:${GOLANG_VERSION} sh -c \ "cd /local; make deps; ${FORMAT_GEN}; make add-license; make shorten-lines; make fix-imports; go mod tidy;" diff --git a/constructor/worker/worker.go b/constructor/worker/worker.go index ea1def9a..1f7d5ce2 100644 --- a/constructor/worker/worker.go +++ b/constructor/worker/worker.go @@ -20,7 +20,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "log" "net/http" "net/url" @@ -877,7 +876,7 @@ func HTTPRequestWorker(rawInput string) (string, error) { _ = resp.Body.Close() }() - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { return "", fmt.Errorf("failed to read response: %w", err) } diff --git a/constructor/worker/worker_test.go b/constructor/worker/worker_test.go index 12952b03..035a1453 100644 --- a/constructor/worker/worker_test.go +++ b/constructor/worker/worker_test.go @@ -19,7 +19,7 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" + "io" "net/http" "net/http/httptest" "os" @@ -1840,7 +1840,7 @@ func TestHTTPRequestWorker(t *testing.T) { assert.Equal(t, test.expectedPath, r.URL.RequestURI()) defer r.Body.Close() - body, err := ioutil.ReadAll(r.Body) + body, err := io.ReadAll(r.Body) assert.NoError(t, err) assert.Equal(t, test.expectedBody, string(body)) diff --git a/examples/server/main.go b/examples/server/main.go index ba2cdaa2..6c41b033 100644 --- a/examples/server/main.go +++ b/examples/server/main.go @@ -40,14 +40,12 @@ func NewBlockchainRouter( networkAPIController := server.NewNetworkAPIController( networkAPIService, asserter, - nil, ) blockAPIService := services.NewBlockAPIService(network) blockAPIController := server.NewBlockAPIController( blockAPIService, asserter, - nil, ) return server.NewRouter(networkAPIController, blockAPIController) diff --git a/go.mod b/go.mod index 3c4a6bec..02d5b6f2 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/coinbase/rosetta-sdk-go -go 1.18 +go 1.19 require ( github.com/DataDog/zstd v1.5.2 @@ -21,7 +21,8 @@ require ( github.com/tidwall/gjson v1.14.2 github.com/tidwall/sjson v1.2.5 github.com/vmihailenco/msgpack/v5 v5.3.5 - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c + golang.org/x/sync v0.5.0 + google.golang.org/grpc v1.61.2 ) require ( @@ -34,7 +35,7 @@ require ( github.com/dgraph-io/ristretto v0.0.3 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/dustin/go-humanize v1.0.0 // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/klauspost/compress v1.12.3 // indirect github.com/mattn/go-colorable v0.1.9 // indirect @@ -46,9 +47,11 @@ require ( github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect - golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect - golang.org/x/net v0.0.0-20220607020251-c690dde0001d // indirect - golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect - google.golang.org/protobuf v1.26.0 // indirect + golang.org/x/crypto v0.15.0 // indirect + golang.org/x/net v0.18.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/text v0.14.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 947d5e32..bcd5a763 100644 --- a/go.sum +++ b/go.sum @@ -63,13 +63,13 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -157,18 +157,18 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8= -golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -179,17 +179,23 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= +google.golang.org/grpc v1.61.2 h1:TzJay21lXCf7BiNFKl7mSskt5DlkKAumAYTs52SpJeo= +google.golang.org/grpc v1.61.2/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/headerforwarder/context_headers.go b/headerforwarder/context.go similarity index 57% rename from headerforwarder/context_headers.go rename to headerforwarder/context.go index a4c1b90d..271fee5d 100644 --- a/headerforwarder/context_headers.go +++ b/headerforwarder/context.go @@ -25,12 +25,19 @@ type contextKey string const requestIDKey = contextKey("request_id") +const outgoingHeadersKey = contextKey("outgoing_headers") + func ContextWithRosettaID(ctx context.Context) context.Context { return context.WithValue(ctx, requestIDKey, uuid.NewString()) } func RosettaIDFromContext(ctx context.Context) string { - return ctx.Value(requestIDKey).(string) + switch val := ctx.Value(requestIDKey).(type) { + case string: + return val + default: + return "" + } } func RosettaIDFromRequest(r *http.Request) string { @@ -41,3 +48,26 @@ func RosettaIDFromRequest(r *http.Request) string { return "" } } + +// RequestWithRequestID adds a unique ID to the request context. A new request is returned that contains the +// new context +func RequestWithRequestID(req *http.Request) *http.Request { + ctx := req.Context() + ctxWithID := ContextWithRosettaID(ctx) + requestWithID := req.WithContext(ctxWithID) + + return requestWithID +} + +func ContextWithOutgoingHeaders(ctx context.Context, headers http.Header) context.Context { + return context.WithValue(ctx, outgoingHeadersKey, headers) +} + +func OutgoingHeadersFromContext(ctx context.Context) http.Header { + switch val := ctx.Value(outgoingHeadersKey).(type) { + case http.Header: + return val + default: + return nil + } +} diff --git a/headerforwarder/forwarder.go b/headerforwarder/forwarder.go index 85cb7814..75b7ae50 100644 --- a/headerforwarder/forwarder.go +++ b/headerforwarder/forwarder.go @@ -15,7 +15,13 @@ package headerforwarder import ( + "context" + "fmt" "net/http" + "strings" + + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" ) // HeaderExtractingTransport is a utility to help a rosetta server forward headers to and from @@ -29,32 +35,48 @@ import ( // // TODO: this should expire entries after a certain amount of time type HeaderForwarder struct { - requestHeaders map[string]http.Header + incomingHeaders map[string]http.Header + outgoingHeaders map[string]http.Header interestingHeaders []string actualTransport http.RoundTripper } -func NewHeaderForwarder(interestingHeaders []string, transport http.RoundTripper) *HeaderForwarder { +func NewHeaderForwarder( + interestingHeaders []string, + transport http.RoundTripper, +) (*HeaderForwarder, error) { + if len(interestingHeaders) == 0 { + return nil, fmt.Errorf("must provide at least one interesting header") + } + return &HeaderForwarder{ - requestHeaders: make(map[string]http.Header), + incomingHeaders: make(map[string]http.Header), + outgoingHeaders: make(map[string]http.Header), interestingHeaders: interestingHeaders, actualTransport: transport, - } + }, nil } -// RoundTrip implements http.RoundTripper and will be used to construct an http Client which -// saves the native node response headers if necessary. -func (hf *HeaderForwarder) RoundTrip(req *http.Request) (*http.Response, error) { - resp, err := hf.actualTransport.RoundTrip(req) +func (hf *HeaderForwarder) WithTransport(transport http.RoundTripper) *HeaderForwarder { + hf.actualTransport = transport + return hf +} - if err == nil && hf.shouldRememberHeaders(req, resp) { - hf.rememberHeaders(req, resp) - } +func (hf *HeaderForwarder) captureOutgoingHeaders(req *http.Request) { + ctx := req.Context() + rosettaRequestID := RosettaIDFromContext(ctx) - return resp, err + hf.outgoingHeaders[rosettaRequestID] = make(http.Header) + + // Only capture interesting headers + for _, interestingHeader := range hf.interestingHeaders { + if _, requestHasHeader := req.Header[http.CanonicalHeaderKey(interestingHeader)]; requestHasHeader { + hf.outgoingHeaders[rosettaRequestID].Set(interestingHeader, req.Header.Get(interestingHeader)) + } + } } -// shouldRememberHeaders is called to determine if response headers should be remembered for a +// shouldRememberHeaders reports whether response headers should be remembered for a // given request. Response headers will only be remembered if the request does not contain all of // the interesting headers and the response contains at least one of the interesting headers. // @@ -82,30 +104,79 @@ func (hf *HeaderForwarder) shouldRememberHeaders(req *http.Request, resp *http.R return !requestHasAllHeaders && responseHasSomeHeaders } -// rememberHeaders is called to save the native node response headers. The request object -// here is a native node request (constructed by go-ethereum for geth-based rosetta implementations). +// rememberHeaders saves the native node response headers. The request object here is a +// native node request (e.g. one constructed by go-ethereum for geth-based rosetta implementations). // The response object is a native node response. func (hf *HeaderForwarder) rememberHeaders(req *http.Request, resp *http.Response) { ctx := req.Context() - // rosettaRequestID := services.osettaIdFromContext(ctx) rosettaRequestID := RosettaIDFromContext(ctx) + // For multiple requests with the same rosetta ID, we want to remember all of the headers + // For repeated response headers, later values will overwrite earlier ones + headersToRemember, exists := hf.incomingHeaders[rosettaRequestID] + if !exists { + headersToRemember = make(http.Header) + } + // Only remember interesting headers - headersToRemember := make(http.Header) for _, interestingHeader := range hf.interestingHeaders { headersToRemember.Set(interestingHeader, resp.Header.Get(interestingHeader)) } - hf.requestHeaders[rosettaRequestID] = headersToRemember + hf.incomingHeaders[rosettaRequestID] = headersToRemember +} + +// shouldRememberMetadata reports whether response metadata should be remembered for a grpc unary +// RPC call. Response metadata will only be remembered if it contains any of the interesting headers. +func (hf *HeaderForwarder) shouldRememberMetadata(ctx context.Context, resp metadata.MD) bool { + rosettaID := RosettaIDFromContext(ctx) + if rosettaID == "" { + return false + } + + // If any of the interesting headers are in the response metadata, remember it + // grpc metadata uses lowercase keys rather than http canonicalized keys + for _, interestingHeader := range hf.interestingHeaders { + if _, responseHasHeader := resp[strings.ToLower(interestingHeader)]; responseHasHeader { + return true + } + } + + return false +} + +// rememberMetadata saves the native node response metadata. The response object is metadata retrieved +// from a native node GRPC unary RPC call. +func (hf *HeaderForwarder) rememberMetadata(ctx context.Context, resp metadata.MD) { + rosettaID := RosettaIDFromContext(ctx) + + // For multiple requests with the same rosetta ID, we want to remember all of the headers + // For repeated response headers, later values will overwrite earlier ones + headersToRemember, exists := hf.incomingHeaders[rosettaID] + if !exists { + headersToRemember = make(http.Header) + } + + for _, interestingHeader := range hf.interestingHeaders { + for _, value := range resp.Get(strings.ToLower(interestingHeader)) { + headersToRemember.Set(interestingHeader, value) + } + } + + hf.incomingHeaders[rosettaID] = headersToRemember } -// GetResponseHeaders returns any native node response headers that were recorded for a request ID. +// GetResponseHeaders returns any headers that should be returned to a rosetta response. These +// consist of native node response headers/metadata that were remembered for a request ID. func (hf *HeaderForwarder) getResponseHeaders(rosettaRequestID string) (http.Header, bool) { - headers, ok := hf.requestHeaders[rosettaRequestID] + headers, ok := hf.incomingHeaders[rosettaRequestID] // Delete the headers from the map after they are retrieved // This is safe to call even if the key doesn't exist - delete(hf.requestHeaders, rosettaRequestID) + delete(hf.incomingHeaders, rosettaRequestID) + + // Also delete the outgoing headers from the map since we are done with them + delete(hf.outgoingHeaders, rosettaRequestID) return headers, ok } @@ -116,27 +187,66 @@ func (hf *HeaderForwarder) getResponseHeaders(rosettaRequestID string) (http.Hea func (hf *HeaderForwarder) HeaderForwarderHandler(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // add a unique ID to the request context, and make a new request for it - requestWithID := hf.WithRequestID(r) + requestWithID := RequestWithRequestID(r) - // Serve the request - // NOTE: ResponseWriter::WriteHeader() WILL be called here, so we can't set headers after this happens - // We include a wrapper around the response writer that allows us to set headers just before - // WriteHeader is called + // Capture outgoing interesting headers + hf.captureOutgoingHeaders(requestWithID) + + // NOTE: for servers using github.com/coinbase/mesh-geth-sdk, ResponseWriter::WriteHeader() WILL + // be called internally, so we can't set headers after this happens. We include a wrapper around the + // response writer that allows us to set headers just before WriteHeader is called wrappedResponseWriter := NewResponseWriter( w, RosettaIDFromRequest(requestWithID), hf.getResponseHeaders, ) + + // Serve the request next.ServeHTTP(wrappedResponseWriter, requestWithID) }) } -// WithRequestID adds a unique ID to the request context. A new request is returned that contains the -// new context -func (hf *HeaderForwarder) WithRequestID(req *http.Request) *http.Request { - ctx := req.Context() - ctxWithID := ContextWithRosettaID(ctx) - requestWithID := req.WithContext(ctxWithID) +// RoundTrip implements http.RoundTripper and will be used to construct an http Client which +// saves the native node response headers if necessary. +func (hf *HeaderForwarder) RoundTrip(req *http.Request) (*http.Response, error) { + // add outgoing headers to the request + if outgoingHeaders, ok := hf.outgoingHeaders[RosettaIDFromRequest(req)]; ok { + for header, values := range outgoingHeaders { + for _, value := range values { + req.Header.Add(header, value) + } + } + } + + resp, err := hf.actualTransport.RoundTrip(req) + + if err == nil && hf.shouldRememberHeaders(req, resp) { + hf.rememberHeaders(req, resp) + } + + return resp, err +} + +func (hf *HeaderForwarder) UnaryClientInterceptor(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + // Capture incoming headers from the grpc call + var header metadata.MD + opts = append(opts, grpc.Header(&header)) + + // Add outgoing headers to the context + if outgoingHeaders, ok := hf.outgoingHeaders[RosettaIDFromContext(ctx)]; ok { + for header, values := range outgoingHeaders { + for _, value := range values { + ctx = metadata.AppendToOutgoingContext(ctx, strings.ToLower(header), value) + } + } + } + + // Invoke the grpc call + err := invoker(ctx, method, req, reply, cc, opts...) + + if hf.shouldRememberMetadata(ctx, header) { + hf.rememberMetadata(ctx, header) + } - return requestWithID + return err } diff --git a/server/api_account.go b/server/api_account.go index a98d4565..af1e881a 100644 --- a/server/api_account.go +++ b/server/api_account.go @@ -17,7 +17,6 @@ package server import ( - "context" "encoding/json" "net/http" "strings" @@ -29,21 +28,18 @@ import ( // A AccountAPIController binds http requests to an api service and writes the service results to // the http response type AccountAPIController struct { - service AccountAPIServicer - asserter *asserter.Asserter - contextFromRequest func(*http.Request) context.Context + service AccountAPIServicer + asserter *asserter.Asserter } // NewAccountAPIController creates a default api controller func NewAccountAPIController( s AccountAPIServicer, asserter *asserter.Asserter, - contextFromRequest func(*http.Request) context.Context, ) Router { return &AccountAPIController{ - service: s, - asserter: asserter, - contextFromRequest: contextFromRequest, + service: s, + asserter: asserter, } } @@ -65,16 +61,6 @@ func (c *AccountAPIController) Routes() Routes { } } -func (c *AccountAPIController) ContextFromRequest(r *http.Request) context.Context { - ctx := r.Context() - - if c.contextFromRequest != nil { - ctx = c.contextFromRequest(r) - } - - return ctx -} - // AccountBalance - Get an Account's Balance func (c *AccountAPIController) AccountBalance(w http.ResponseWriter, r *http.Request) { accountBalanceRequest := &types.AccountBalanceRequest{} @@ -95,7 +81,7 @@ func (c *AccountAPIController) AccountBalance(w http.ResponseWriter, r *http.Req return } - result, serviceErr := c.service.AccountBalance(c.ContextFromRequest(r), accountBalanceRequest) + result, serviceErr := c.service.AccountBalance(r.Context(), accountBalanceRequest) if serviceErr != nil { EncodeJSONResponse(serviceErr, http.StatusInternalServerError, w) @@ -125,7 +111,7 @@ func (c *AccountAPIController) AccountCoins(w http.ResponseWriter, r *http.Reque return } - result, serviceErr := c.service.AccountCoins(c.ContextFromRequest(r), accountCoinsRequest) + result, serviceErr := c.service.AccountCoins(r.Context(), accountCoinsRequest) if serviceErr != nil { EncodeJSONResponse(serviceErr, http.StatusInternalServerError, w) diff --git a/server/api_block.go b/server/api_block.go index a3d22732..a3fe4cf6 100644 --- a/server/api_block.go +++ b/server/api_block.go @@ -17,7 +17,6 @@ package server import ( - "context" "encoding/json" "net/http" "strings" @@ -29,21 +28,18 @@ import ( // A BlockAPIController binds http requests to an api service and writes the service results to the // http response type BlockAPIController struct { - service BlockAPIServicer - asserter *asserter.Asserter - contextFromRequest func(*http.Request) context.Context + service BlockAPIServicer + asserter *asserter.Asserter } // NewBlockAPIController creates a default api controller func NewBlockAPIController( s BlockAPIServicer, asserter *asserter.Asserter, - contextFromRequest func(*http.Request) context.Context, ) Router { return &BlockAPIController{ - service: s, - asserter: asserter, - contextFromRequest: contextFromRequest, + service: s, + asserter: asserter, } } @@ -65,16 +61,6 @@ func (c *BlockAPIController) Routes() Routes { } } -func (c *BlockAPIController) ContextFromRequest(r *http.Request) context.Context { - ctx := r.Context() - - if c.contextFromRequest != nil { - ctx = c.contextFromRequest(r) - } - - return ctx -} - // Block - Get a Block func (c *BlockAPIController) Block(w http.ResponseWriter, r *http.Request) { blockRequest := &types.BlockRequest{} @@ -95,7 +81,7 @@ func (c *BlockAPIController) Block(w http.ResponseWriter, r *http.Request) { return } - result, serviceErr := c.service.Block(c.ContextFromRequest(r), blockRequest) + result, serviceErr := c.service.Block(r.Context(), blockRequest) if serviceErr != nil { EncodeJSONResponse(serviceErr, http.StatusInternalServerError, w) @@ -125,10 +111,7 @@ func (c *BlockAPIController) BlockTransaction(w http.ResponseWriter, r *http.Req return } - result, serviceErr := c.service.BlockTransaction( - c.ContextFromRequest(r), - blockTransactionRequest, - ) + result, serviceErr := c.service.BlockTransaction(r.Context(), blockTransactionRequest) if serviceErr != nil { EncodeJSONResponse(serviceErr, http.StatusInternalServerError, w) diff --git a/server/api_call.go b/server/api_call.go index 7e965636..20abff66 100644 --- a/server/api_call.go +++ b/server/api_call.go @@ -17,7 +17,6 @@ package server import ( - "context" "encoding/json" "net/http" "strings" @@ -29,21 +28,18 @@ import ( // A CallAPIController binds http requests to an api service and writes the service results to the // http response type CallAPIController struct { - service CallAPIServicer - asserter *asserter.Asserter - contextFromRequest func(*http.Request) context.Context + service CallAPIServicer + asserter *asserter.Asserter } // NewCallAPIController creates a default api controller func NewCallAPIController( s CallAPIServicer, asserter *asserter.Asserter, - contextFromRequest func(*http.Request) context.Context, ) Router { return &CallAPIController{ - service: s, - asserter: asserter, - contextFromRequest: contextFromRequest, + service: s, + asserter: asserter, } } @@ -59,16 +55,6 @@ func (c *CallAPIController) Routes() Routes { } } -func (c *CallAPIController) ContextFromRequest(r *http.Request) context.Context { - ctx := r.Context() - - if c.contextFromRequest != nil { - ctx = c.contextFromRequest(r) - } - - return ctx -} - // Call - Make a Network-Specific Procedure Call func (c *CallAPIController) Call(w http.ResponseWriter, r *http.Request) { callRequest := &types.CallRequest{} @@ -89,7 +75,7 @@ func (c *CallAPIController) Call(w http.ResponseWriter, r *http.Request) { return } - result, serviceErr := c.service.Call(c.ContextFromRequest(r), callRequest) + result, serviceErr := c.service.Call(r.Context(), callRequest) if serviceErr != nil { EncodeJSONResponse(serviceErr, http.StatusInternalServerError, w) diff --git a/server/api_construction.go b/server/api_construction.go index f1d91c2a..d47d45a0 100644 --- a/server/api_construction.go +++ b/server/api_construction.go @@ -17,7 +17,6 @@ package server import ( - "context" "encoding/json" "net/http" "strings" @@ -29,21 +28,18 @@ import ( // A ConstructionAPIController binds http requests to an api service and writes the service results // to the http response type ConstructionAPIController struct { - service ConstructionAPIServicer - asserter *asserter.Asserter - contextFromRequest func(*http.Request) context.Context + service ConstructionAPIServicer + asserter *asserter.Asserter } // NewConstructionAPIController creates a default api controller func NewConstructionAPIController( s ConstructionAPIServicer, asserter *asserter.Asserter, - contextFromRequest func(*http.Request) context.Context, ) Router { return &ConstructionAPIController{ - service: s, - asserter: asserter, - contextFromRequest: contextFromRequest, + service: s, + asserter: asserter, } } @@ -101,16 +97,6 @@ func (c *ConstructionAPIController) Routes() Routes { } } -func (c *ConstructionAPIController) ContextFromRequest(r *http.Request) context.Context { - ctx := r.Context() - - if c.contextFromRequest != nil { - ctx = c.contextFromRequest(r) - } - - return ctx -} - // ConstructionCombine - Create Network Transaction from Signatures func (c *ConstructionAPIController) ConstructionCombine(w http.ResponseWriter, r *http.Request) { constructionCombineRequest := &types.ConstructionCombineRequest{} @@ -131,10 +117,7 @@ func (c *ConstructionAPIController) ConstructionCombine(w http.ResponseWriter, r return } - result, serviceErr := c.service.ConstructionCombine( - c.ContextFromRequest(r), - constructionCombineRequest, - ) + result, serviceErr := c.service.ConstructionCombine(r.Context(), constructionCombineRequest) if serviceErr != nil { EncodeJSONResponse(serviceErr, http.StatusInternalServerError, w) @@ -164,10 +147,7 @@ func (c *ConstructionAPIController) ConstructionDerive(w http.ResponseWriter, r return } - result, serviceErr := c.service.ConstructionDerive( - c.ContextFromRequest(r), - constructionDeriveRequest, - ) + result, serviceErr := c.service.ConstructionDerive(r.Context(), constructionDeriveRequest) if serviceErr != nil { EncodeJSONResponse(serviceErr, http.StatusInternalServerError, w) @@ -197,10 +177,7 @@ func (c *ConstructionAPIController) ConstructionHash(w http.ResponseWriter, r *h return } - result, serviceErr := c.service.ConstructionHash( - c.ContextFromRequest(r), - constructionHashRequest, - ) + result, serviceErr := c.service.ConstructionHash(r.Context(), constructionHashRequest) if serviceErr != nil { EncodeJSONResponse(serviceErr, http.StatusInternalServerError, w) @@ -230,10 +207,7 @@ func (c *ConstructionAPIController) ConstructionMetadata(w http.ResponseWriter, return } - result, serviceErr := c.service.ConstructionMetadata( - c.ContextFromRequest(r), - constructionMetadataRequest, - ) + result, serviceErr := c.service.ConstructionMetadata(r.Context(), constructionMetadataRequest) if serviceErr != nil { EncodeJSONResponse(serviceErr, http.StatusInternalServerError, w) @@ -263,10 +237,7 @@ func (c *ConstructionAPIController) ConstructionParse(w http.ResponseWriter, r * return } - result, serviceErr := c.service.ConstructionParse( - c.ContextFromRequest(r), - constructionParseRequest, - ) + result, serviceErr := c.service.ConstructionParse(r.Context(), constructionParseRequest) if serviceErr != nil { EncodeJSONResponse(serviceErr, http.StatusInternalServerError, w) @@ -296,10 +267,7 @@ func (c *ConstructionAPIController) ConstructionPayloads(w http.ResponseWriter, return } - result, serviceErr := c.service.ConstructionPayloads( - c.ContextFromRequest(r), - constructionPayloadsRequest, - ) + result, serviceErr := c.service.ConstructionPayloads(r.Context(), constructionPayloadsRequest) if serviceErr != nil { EncodeJSONResponse(serviceErr, http.StatusInternalServerError, w) @@ -330,7 +298,7 @@ func (c *ConstructionAPIController) ConstructionPreprocess(w http.ResponseWriter } result, serviceErr := c.service.ConstructionPreprocess( - c.ContextFromRequest(r), + r.Context(), constructionPreprocessRequest, ) if serviceErr != nil { @@ -362,10 +330,7 @@ func (c *ConstructionAPIController) ConstructionSubmit(w http.ResponseWriter, r return } - result, serviceErr := c.service.ConstructionSubmit( - c.ContextFromRequest(r), - constructionSubmitRequest, - ) + result, serviceErr := c.service.ConstructionSubmit(r.Context(), constructionSubmitRequest) if serviceErr != nil { EncodeJSONResponse(serviceErr, http.StatusInternalServerError, w) diff --git a/server/api_events.go b/server/api_events.go index 68dbeb1b..73a1d5d5 100644 --- a/server/api_events.go +++ b/server/api_events.go @@ -17,7 +17,6 @@ package server import ( - "context" "encoding/json" "net/http" "strings" @@ -29,21 +28,18 @@ import ( // A EventsAPIController binds http requests to an api service and writes the service results to the // http response type EventsAPIController struct { - service EventsAPIServicer - asserter *asserter.Asserter - contextFromRequest func(*http.Request) context.Context + service EventsAPIServicer + asserter *asserter.Asserter } // NewEventsAPIController creates a default api controller func NewEventsAPIController( s EventsAPIServicer, asserter *asserter.Asserter, - contextFromRequest func(*http.Request) context.Context, ) Router { return &EventsAPIController{ - service: s, - asserter: asserter, - contextFromRequest: contextFromRequest, + service: s, + asserter: asserter, } } @@ -59,16 +55,6 @@ func (c *EventsAPIController) Routes() Routes { } } -func (c *EventsAPIController) ContextFromRequest(r *http.Request) context.Context { - ctx := r.Context() - - if c.contextFromRequest != nil { - ctx = c.contextFromRequest(r) - } - - return ctx -} - // EventsBlocks - [INDEXER] Get a range of BlockEvents func (c *EventsAPIController) EventsBlocks(w http.ResponseWriter, r *http.Request) { eventsBlocksRequest := &types.EventsBlocksRequest{} @@ -89,7 +75,7 @@ func (c *EventsAPIController) EventsBlocks(w http.ResponseWriter, r *http.Reques return } - result, serviceErr := c.service.EventsBlocks(c.ContextFromRequest(r), eventsBlocksRequest) + result, serviceErr := c.service.EventsBlocks(r.Context(), eventsBlocksRequest) if serviceErr != nil { EncodeJSONResponse(serviceErr, http.StatusInternalServerError, w) diff --git a/server/api_mempool.go b/server/api_mempool.go index 789f2b9f..774fb176 100644 --- a/server/api_mempool.go +++ b/server/api_mempool.go @@ -17,7 +17,6 @@ package server import ( - "context" "encoding/json" "net/http" "strings" @@ -29,21 +28,18 @@ import ( // A MempoolAPIController binds http requests to an api service and writes the service results to // the http response type MempoolAPIController struct { - service MempoolAPIServicer - asserter *asserter.Asserter - contextFromRequest func(*http.Request) context.Context + service MempoolAPIServicer + asserter *asserter.Asserter } // NewMempoolAPIController creates a default api controller func NewMempoolAPIController( s MempoolAPIServicer, asserter *asserter.Asserter, - contextFromRequest func(*http.Request) context.Context, ) Router { return &MempoolAPIController{ - service: s, - asserter: asserter, - contextFromRequest: contextFromRequest, + service: s, + asserter: asserter, } } @@ -65,16 +61,6 @@ func (c *MempoolAPIController) Routes() Routes { } } -func (c *MempoolAPIController) ContextFromRequest(r *http.Request) context.Context { - ctx := r.Context() - - if c.contextFromRequest != nil { - ctx = c.contextFromRequest(r) - } - - return ctx -} - // Mempool - Get All Mempool Transactions func (c *MempoolAPIController) Mempool(w http.ResponseWriter, r *http.Request) { networkRequest := &types.NetworkRequest{} @@ -95,7 +81,7 @@ func (c *MempoolAPIController) Mempool(w http.ResponseWriter, r *http.Request) { return } - result, serviceErr := c.service.Mempool(c.ContextFromRequest(r), networkRequest) + result, serviceErr := c.service.Mempool(r.Context(), networkRequest) if serviceErr != nil { EncodeJSONResponse(serviceErr, http.StatusInternalServerError, w) @@ -125,10 +111,7 @@ func (c *MempoolAPIController) MempoolTransaction(w http.ResponseWriter, r *http return } - result, serviceErr := c.service.MempoolTransaction( - c.ContextFromRequest(r), - mempoolTransactionRequest, - ) + result, serviceErr := c.service.MempoolTransaction(r.Context(), mempoolTransactionRequest) if serviceErr != nil { EncodeJSONResponse(serviceErr, http.StatusInternalServerError, w) diff --git a/server/api_network.go b/server/api_network.go index 323c8aa9..75a8f0c1 100644 --- a/server/api_network.go +++ b/server/api_network.go @@ -17,7 +17,6 @@ package server import ( - "context" "encoding/json" "net/http" "strings" @@ -29,21 +28,18 @@ import ( // A NetworkAPIController binds http requests to an api service and writes the service results to // the http response type NetworkAPIController struct { - service NetworkAPIServicer - asserter *asserter.Asserter - contextFromRequest func(*http.Request) context.Context + service NetworkAPIServicer + asserter *asserter.Asserter } // NewNetworkAPIController creates a default api controller func NewNetworkAPIController( s NetworkAPIServicer, asserter *asserter.Asserter, - contextFromRequest func(*http.Request) context.Context, ) Router { return &NetworkAPIController{ - service: s, - asserter: asserter, - contextFromRequest: contextFromRequest, + service: s, + asserter: asserter, } } @@ -71,16 +67,6 @@ func (c *NetworkAPIController) Routes() Routes { } } -func (c *NetworkAPIController) ContextFromRequest(r *http.Request) context.Context { - ctx := r.Context() - - if c.contextFromRequest != nil { - ctx = c.contextFromRequest(r) - } - - return ctx -} - // NetworkList - Get List of Available Networks func (c *NetworkAPIController) NetworkList(w http.ResponseWriter, r *http.Request) { metadataRequest := &types.MetadataRequest{} @@ -101,7 +87,7 @@ func (c *NetworkAPIController) NetworkList(w http.ResponseWriter, r *http.Reques return } - result, serviceErr := c.service.NetworkList(c.ContextFromRequest(r), metadataRequest) + result, serviceErr := c.service.NetworkList(r.Context(), metadataRequest) if serviceErr != nil { EncodeJSONResponse(serviceErr, http.StatusInternalServerError, w) @@ -131,7 +117,7 @@ func (c *NetworkAPIController) NetworkOptions(w http.ResponseWriter, r *http.Req return } - result, serviceErr := c.service.NetworkOptions(c.ContextFromRequest(r), networkRequest) + result, serviceErr := c.service.NetworkOptions(r.Context(), networkRequest) if serviceErr != nil { EncodeJSONResponse(serviceErr, http.StatusInternalServerError, w) @@ -161,7 +147,7 @@ func (c *NetworkAPIController) NetworkStatus(w http.ResponseWriter, r *http.Requ return } - result, serviceErr := c.service.NetworkStatus(c.ContextFromRequest(r), networkRequest) + result, serviceErr := c.service.NetworkStatus(r.Context(), networkRequest) if serviceErr != nil { EncodeJSONResponse(serviceErr, http.StatusInternalServerError, w) diff --git a/server/api_search.go b/server/api_search.go index 70ea7e54..a9e02549 100644 --- a/server/api_search.go +++ b/server/api_search.go @@ -17,7 +17,6 @@ package server import ( - "context" "encoding/json" "net/http" "strings" @@ -29,21 +28,18 @@ import ( // A SearchAPIController binds http requests to an api service and writes the service results to the // http response type SearchAPIController struct { - service SearchAPIServicer - asserter *asserter.Asserter - contextFromRequest func(*http.Request) context.Context + service SearchAPIServicer + asserter *asserter.Asserter } // NewSearchAPIController creates a default api controller func NewSearchAPIController( s SearchAPIServicer, asserter *asserter.Asserter, - contextFromRequest func(*http.Request) context.Context, ) Router { return &SearchAPIController{ - service: s, - asserter: asserter, - contextFromRequest: contextFromRequest, + service: s, + asserter: asserter, } } @@ -59,16 +55,6 @@ func (c *SearchAPIController) Routes() Routes { } } -func (c *SearchAPIController) ContextFromRequest(r *http.Request) context.Context { - ctx := r.Context() - - if c.contextFromRequest != nil { - ctx = c.contextFromRequest(r) - } - - return ctx -} - // SearchTransactions - [INDEXER] Search for Transactions func (c *SearchAPIController) SearchTransactions(w http.ResponseWriter, r *http.Request) { searchTransactionsRequest := &types.SearchTransactionsRequest{} @@ -89,10 +75,7 @@ func (c *SearchAPIController) SearchTransactions(w http.ResponseWriter, r *http. return } - result, serviceErr := c.service.SearchTransactions( - c.ContextFromRequest(r), - searchTransactionsRequest, - ) + result, serviceErr := c.service.SearchTransactions(r.Context(), searchTransactionsRequest) if serviceErr != nil { EncodeJSONResponse(serviceErr, http.StatusInternalServerError, w) diff --git a/server/routers.go b/server/routers.go index a762117d..27e8b95c 100644 --- a/server/routers.go +++ b/server/routers.go @@ -17,7 +17,6 @@ package server import ( - "context" "encoding/json" "net/http" @@ -38,7 +37,6 @@ type Routes []Route // Router defines the required methods for retrieving api routes type Router interface { Routes() Routes - ContextFromRequest(*http.Request) context.Context } // CorsMiddleware handles CORS and ensures OPTIONS requests are diff --git a/storage/database/badger_database.go b/storage/database/badger_database.go index 669867d9..3152e69c 100644 --- a/storage/database/badger_database.go +++ b/storage/database/badger_database.go @@ -19,7 +19,6 @@ import ( "context" "errors" "fmt" - "io/ioutil" "log" "os" "os/exec" @@ -608,7 +607,7 @@ func decompressAndSave( ) } - err = ioutil.WriteFile( + err = os.WriteFile( path.Join(tmpDir, types.Hash(string(k))), decompressed, os.FileMode(utils.DefaultFilePermissions), @@ -634,7 +633,7 @@ func decompressAndEncode( namespace string, encoder *encoder.Encoder, ) (float64, float64, float64, error) { - decompressed, err := ioutil.ReadFile(path) // #nosec G304 + decompressed, err := os.ReadFile(path) // #nosec G304 if err != nil { return -1, -1, -1, fmt.Errorf( "unable to read decompress file %s: %w", diff --git a/storage/encoder/encoder.go b/storage/encoder/encoder.go index 528f2a28..2f8b4a0c 100644 --- a/storage/encoder/encoder.go +++ b/storage/encoder/encoder.go @@ -19,8 +19,8 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "log" + "os" "path" "strconv" @@ -66,7 +66,7 @@ func NewEncoder( ) (*Encoder, error) { dicts := map[string][]byte{} for _, entry := range entries { - b, err := ioutil.ReadFile(path.Clean(entry.DictionaryPath)) + b, err := os.ReadFile(path.Clean(entry.DictionaryPath)) if err != nil { return nil, fmt.Errorf( "unable to load dictionary %s: %w", diff --git a/storage/modules/balance_storage_test.go b/storage/modules/balance_storage_test.go index d1e40001..db227202 100644 --- a/storage/modules/balance_storage_test.go +++ b/storage/modules/balance_storage_test.go @@ -18,8 +18,8 @@ import ( "context" "encoding/json" "errors" - "io/ioutil" "math/big" + "os" "path" "testing" @@ -1087,7 +1087,7 @@ func TestBootstrapBalances(t *testing.T) { assert.NoError( t, - ioutil.WriteFile(bootstrapBalancesFile, file, utils.DefaultFilePermissions), + os.WriteFile(bootstrapBalancesFile, file, utils.DefaultFilePermissions), ) t.Run("run before initializing helper/handler", func(t *testing.T) { @@ -1170,7 +1170,7 @@ func TestBootstrapBalances(t *testing.T) { t.Run("Invalid file contents", func(t *testing.T) { assert.NoError( t, - ioutil.WriteFile( + os.WriteFile( bootstrapBalancesFile, []byte("bad file"), utils.DefaultFilePermissions, @@ -1205,7 +1205,7 @@ func TestBootstrapBalances(t *testing.T) { assert.NoError( t, - ioutil.WriteFile(bootstrapBalancesFile, file, utils.DefaultFilePermissions), + os.WriteFile(bootstrapBalancesFile, file, utils.DefaultFilePermissions), ) err = storage.BootstrapBalances( @@ -1236,7 +1236,7 @@ func TestBootstrapBalances(t *testing.T) { assert.NoError( t, - ioutil.WriteFile(bootstrapBalancesFile, file, utils.DefaultFilePermissions), + os.WriteFile(bootstrapBalancesFile, file, utils.DefaultFilePermissions), ) err = storage.BootstrapBalances( diff --git a/templates/client/api.mustache b/templates/client/api.mustache index a2e8243f..d0247209 100644 --- a/templates/client/api.mustache +++ b/templates/client/api.mustache @@ -4,7 +4,6 @@ package {{packageName}} {{#operations}} import ( _context "context" - _ioutil "io/ioutil" _nethttp "net/http" "fmt" "io" @@ -83,13 +82,13 @@ func (a *{{{classname}}}Service) {{{nickname}}}(ctx _context.Context{{#hasParams return nil, nil, fmt.Errorf("failed to call API: %w", err) } - localVarBody, err := _ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) defer func() { _, _ = io.Copy(io.Discard, localVarHTTPResponse.Body) _ = localVarHTTPResponse.Body.Close() }() if err != nil { - return nil, nil, fmt.Errorf("failed to read response: %w", err) + return nil, nil, fmt.Errorf("failed to read response: %w", err) } switch localVarHTTPResponse.StatusCode { diff --git a/templates/go.mod.types b/templates/go.mod.types index c370901b..a634a255 100644 --- a/templates/go.mod.types +++ b/templates/go.mod.types @@ -1,3 +1,3 @@ module github.com/coinbase/rosetta-sdk-go/types -go 1.18 \ No newline at end of file +go 1.19 diff --git a/templates/server/controller-api.mustache b/templates/server/controller-api.mustache index 5d0f422a..1fc8ad37 100644 --- a/templates/server/controller-api.mustache +++ b/templates/server/controller-api.mustache @@ -2,7 +2,6 @@ package {{packageName}} import ( - "context" "encoding/json" "net/http" "strings" @@ -13,21 +12,18 @@ import ( // A {{classname}}Controller binds http requests to an api service and writes the service results to the http response type {{classname}}Controller struct { - service {{classname}}Servicer - asserter *asserter.Asserter - contextFromRequest func(*http.Request) context.Context + service {{classname}}Servicer + asserter *asserter.Asserter } // New{{classname}}Controller creates a default api controller func New{{classname}}Controller( s {{classname}}Servicer, asserter *asserter.Asserter, - contextFromRequest func(*http.Request) context.Context, ) Router { return &{{classname}}Controller{ service: s, asserter: asserter, - contextFromRequest: contextFromRequest, } } @@ -41,16 +37,6 @@ func (c *{{classname}}Controller) Routes() Routes { c.{{operationId}}, },{{/operation}}{{/operations}} } -} - -func (c *{{classname}}Controller) ContextFromRequest(r *http.Request) context.Context { - ctx := r.Context() - - if c.contextFromRequest != nil { - ctx = c.contextFromRequest(r) - } - - return ctx }{{#operations}}{{#operation}} // {{nickname}} - {{{summary}}} @@ -75,7 +61,7 @@ func (c *{{classname}}Controller) {{nickname}}(w http.ResponseWriter, r *http.Re } {{/isBodyParam}}{{/allParams}} - result, serviceErr := c.service.{{nickname}}(c.ContextFromRequest(r), {{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) + result, serviceErr := c.service.{{nickname}}(r.Context(), {{#allParams}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) if serviceErr != nil { EncodeJSONResponse(serviceErr, http.StatusInternalServerError, w) diff --git a/templates/server/routers.mustache b/templates/server/routers.mustache index c0046c08..8394a55e 100644 --- a/templates/server/routers.mustache +++ b/templates/server/routers.mustache @@ -2,7 +2,6 @@ package {{packageName}} import ( - "context" "encoding/json" "net/http" @@ -23,7 +22,6 @@ type Routes []Route // Router defines the required methods for retrieving api routes type Router interface { Routes() Routes - ContextFromRequest(*http.Request) context.Context } // CorsMiddleware handles CORS and ensures OPTIONS requests are diff --git a/types/go.mod b/types/go.mod index 6b93da21..01c91f39 100644 --- a/types/go.mod +++ b/types/go.mod @@ -1,5 +1,5 @@ module github.com/coinbase/rosetta-sdk-go/types -go 1.18 +go 1.19 require github.com/mitchellh/mapstructure v1.5.0 diff --git a/utils/utils.go b/utils/utils.go index 402eddaa..a0c5b923 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -21,7 +21,6 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" "log" "math/big" "os" @@ -86,7 +85,7 @@ var ( // CreateTempDir creates a directory in // /tmp for usage within testing. func CreateTempDir() (string, error) { - storageDir, err := ioutil.TempDir("", "") + storageDir, err := os.MkdirTemp("", "") if err != nil { return "", fmt.Errorf("failed to create temporary directory: %w", err) } @@ -123,7 +122,7 @@ func Equal(a interface{}, b interface{}) bool { // SerializeAndWrite attempts to serialize the provided object // into a file at filePath. func SerializeAndWrite(filePath string, object interface{}) error { - err := ioutil.WriteFile( + err := os.WriteFile( filePath, []byte(types.PrettyPrintStruct(object)), os.FileMode(DefaultFilePermissions), @@ -138,7 +137,7 @@ func SerializeAndWrite(filePath string, object interface{}) error { // LoadAndParse reads the file at the provided path // and attempts to unmarshal it into output. func LoadAndParse(filePath string, output interface{}) error { - b, err := ioutil.ReadFile(path.Clean(filePath)) + b, err := os.ReadFile(path.Clean(filePath)) if err != nil { return fmt.Errorf("unable to load file %s: %w", filePath, err) }