Skip to content

Commit

Permalink
run tests in branch
Browse files Browse the repository at this point in the history
  • Loading branch information
boecklim committed Nov 16, 2023
1 parent 72a49c9 commit 65bd1e8
Show file tree
Hide file tree
Showing 4 changed files with 331 additions and 299 deletions.
300 changes: 12 additions & 288 deletions test/arc_txt_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,12 @@ import (
"testing"
"time"

"github.com/bitcoin-sv/arc/api"
"github.com/bitcoin-sv/arc/api/handler"
"github.com/bitcoin-sv/arc/metamorph/metamorph_api"
"github.com/bitcoinsv/bsvd/bsvec"
"github.com/bitcoinsv/bsvutil"
"github.com/libsv/go-bk/bec"
"github.com/libsv/go-bt/v2"
"github.com/libsv/go-bt/v2/bscript"
"github.com/libsv/go-bt/v2/unlocker"
"github.com/stretchr/testify/require"
)

type Response struct {
Expand All @@ -45,6 +41,11 @@ type TxStatusResponse struct {
Txid string `json:"txid"`
}

var (
address string
privateKey string
)

func TestMain(m *testing.M) {
info, err := bitcoind.GetInfo()
if err != nil {
Expand All @@ -53,6 +54,13 @@ func TestMain(m *testing.M) {

log.Printf("current block height: %d", info.Blocks)

address, privateKey, err := getNewWalletAddress()
if err != nil {
log.Fatalf("failed to get new wallet address: %v", err)
}
log.Println(fmt.Sprintf("new address: %s", address))
log.Println(fmt.Sprintf("new private key: %s", privateKey))

os.Exit(m.Run())
}

Expand Down Expand Up @@ -104,181 +112,7 @@ func createTx(privateKey string, address string, utxo NodeUnspentUtxo) (*bt.Tx,
return tx, nil
}

func TestPostCallbackToken(t *testing.T) {
tt := []struct {
name string
}{
{
name: "post transaction with callback url and token",
},
}

for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
address, privateKey := getNewWalletAddress(t)

generate(t, 100)

t.Logf("generated address: %s", address)

sendToAddress(t, address, 0.001)

txID := sendToAddress(t, address, 0.02)
t.Logf("sent 0.02 BSV to: %s", txID)

hash := generate(t, 1)
t.Logf("generated 1 block: %s", hash)

utxos := getUtxos(t, address)
require.True(t, len(utxos) > 0, "No UTXOs available for the address")

tx, err := createTx(privateKey, address, utxos[0])
require.NoError(t, err)

url := "http://arc:9090/"

arcClient, err := api.NewClientWithResponses(url)
require.NoError(t, err)

ctx := context.Background()

hostname, err := os.Hostname()
require.NoError(t, err)

waitForStatus := api.WaitForStatus(metamorph_api.Status_SEEN_ON_NETWORK)
params := &api.POSTTransactionParams{
XWaitForStatus: &waitForStatus,
XCallbackUrl: handler.PtrTo(fmt.Sprintf("http://%s:9000/callback", hostname)),
XCallbackToken: handler.PtrTo("1234"),
}

arcBody := api.POSTTransactionJSONRequestBody{
RawTx: hex.EncodeToString(tx.ExtendedBytes()),
}

var response *api.POSTTransactionResponse
response, err = arcClient.POSTTransactionWithResponse(ctx, params, arcBody)
require.NoError(t, err)

require.Equal(t, http.StatusOK, response.StatusCode())
require.NotNil(t, response.JSON200)
require.Equal(t, "SEEN_ON_NETWORK", response.JSON200.TxStatus)

callbackReceivedChan := make(chan *api.TransactionStatus, 2)
errChan := make(chan error, 2)

expectedAuthHeader := "Bearer 1234"
srv := &http.Server{Addr: ":9000"}
defer func() {
t.Log("shutting down callback listener")
if err = srv.Shutdown(context.TODO()); err != nil {
panic(err)
}
}()

iterations := 0
http.HandleFunc("/callback", func(w http.ResponseWriter, req *http.Request) {

defer func() {
err := req.Body.Close()
if err != nil {
t.Log("failed to close body")
}
}()

bodyBytes, err := io.ReadAll(req.Body)
if err != nil {
errChan <- err
}

var status api.TransactionStatus
err = json.Unmarshal(bodyBytes, &status)
if err != nil {
errChan <- err
}

if expectedAuthHeader != req.Header.Get("Authorization") {
errChan <- fmt.Errorf("auth header %s not as expected %s", expectedAuthHeader, req.Header.Get("Authorization"))
}

// Let ARC send the callback 2 times. First one fails.
if iterations == 0 {
t.Log("callback received, responding bad request")

err = respondToCallback(w, false)
if err != nil {
t.Fatalf("Failed to respond to callback: %v", err)
}

callbackReceivedChan <- &status

iterations++
return
}

t.Log("callback received, responding success")

err = respondToCallback(w, true)
if err != nil {
t.Fatalf("Failed to respond to callback: %v", err)
}
callbackReceivedChan <- &status
})

go func(server *http.Server) {
t.Log("starting callback server")
err = server.ListenAndServe()
if err != nil {
return
}
}(srv)

generate(t, 10)

var statusResopnse *api.GETTransactionStatusResponse
statusResopnse, err = arcClient.GETTransactionStatusWithResponse(ctx, response.JSON200.Txid)

for i := 0; i <= 1; i++ {
t.Logf("callback iteration %d", i)
select {
case callback := <-callbackReceivedChan:
require.Equal(t, statusResopnse.JSON200.Txid, callback.Txid)
require.Equal(t, statusResopnse.JSON200.BlockHeight, callback.BlockHeight)
require.Equal(t, statusResopnse.JSON200.BlockHash, callback.BlockHash)
case err := <-errChan:
t.Fatalf("callback received - failed to parse callback %v", err)
case <-time.NewTicker(time.Second * 15).C:
t.Fatal("callback not received")
}
}
})
}
}

func respondToCallback(w http.ResponseWriter, success bool) error {
resp := make(map[string]string)
if success {
resp["message"] = "Success"
w.WriteHeader(http.StatusOK)
} else {
resp["message"] = "Bad Request"
w.WriteHeader(http.StatusBadRequest)
}

jsonResp, err := json.Marshal(resp)
if err != nil {
return err
}

_, err = w.Write(jsonResp)
if err != nil {
return err
}
return nil
}

func TestHttpPost(t *testing.T) {
address, privateKey := getNewWalletAddress(t)

generate(t, 100)

Expand Down Expand Up @@ -462,113 +296,3 @@ func TestHttpPost(t *testing.T) {
fmt.Println("Transaction status:", statusResponse.TxStatus)

}

func TestDoubleSpend(t *testing.T) {
tt := []struct {
name string
extFormat bool
}{
{
name: "submit tx with a double spend tx before and after tx got mined - std format",
extFormat: false,
},
{
name: "submit tx with a double spend tx before and after tx got mined - ext format",
extFormat: true,
},
}

for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
address, privateKey := getNewWalletAddress(t)

generate(t, 100)

t.Logf("generated address: %s", address)

sendToAddress(t, address, 0.001)

txID := sendToAddress(t, address, 0.02)
t.Logf("sent 0.02 BSV to: %s", txID)

hash := generate(t, 1)
t.Logf("generated 1 block: %s", hash)

utxos := getUtxos(t, address)
require.True(t, len(utxos) > 0, "No UTXOs available for the address")

tx, err := createTx(privateKey, address, utxos[0])
require.NoError(t, err)

url := "http://arc:9090/"

arcClient, err := api.NewClientWithResponses(url)
require.NoError(t, err)

ctx := context.Background()
waitForStatus := api.WaitForStatus(metamorph_api.Status_SEEN_ON_NETWORK)
params := &api.POSTTransactionParams{
XWaitForStatus: &waitForStatus,
}

arcBody := api.POSTTransactionJSONRequestBody{
RawTx: hex.EncodeToString(tx.ExtendedBytes()),
}

// submit first transaction
var response *api.POSTTransactionResponse
response, err = arcClient.POSTTransactionWithResponse(ctx, params, arcBody)
require.NoError(t, err)

require.Equal(t, http.StatusOK, response.StatusCode())
require.NotNil(t, response.JSON200)
require.Equal(t, "SEEN_ON_NETWORK", response.JSON200.TxStatus)

// send double spending transaction when first tx is in mempool
arcBodyMempool := getArcBody(t, privateKey, utxos[0], tc.extFormat)

var responseMempool *api.POSTTransactionResponse
responseMempool, err = arcClient.POSTTransactionWithResponse(ctx, params, arcBodyMempool)
require.NoError(t, err)

require.Equal(t, http.StatusOK, responseMempool.StatusCode())
require.NotNil(t, responseMempool.JSON200)
require.Equal(t, "REJECTED", responseMempool.JSON200.TxStatus)

generate(t, 10)
var statusResponse *api.GETTransactionStatusResponse
statusResponse, err = arcClient.GETTransactionStatusWithResponse(ctx, response.JSON200.Txid)

require.Equal(t, handler.PtrTo("MINED"), statusResponse.JSON200.TxStatus)
require.NotNil(t, statusResponse.JSON200.MerklePath)

// send double spending transaction when first tx is mined
arcBodyMined := getArcBody(t, privateKey, utxos[0], tc.extFormat)

var responseMined *api.POSTTransactionResponse
responseMempool, err = arcClient.POSTTransactionWithResponse(ctx, params, arcBodyMined)
require.NoError(t, err)

require.Equal(t, http.StatusOK, responseMined.StatusCode())
require.NotNil(t, responseMined.JSON200)
require.Equal(t, "REJECTED", responseMined.JSON200.TxStatus)
})
}
}

func getArcBody(t *testing.T, privateKey string, utxo NodeUnspentUtxo, extFormat bool) api.POSTTransactionJSONRequestBody {
sendToAddress, _ := getNewWalletAddress(t)

tx1, err := createTx(privateKey, sendToAddress, utxo)
require.NoError(t, err)
var arcBodyTx string
if extFormat {
arcBodyTx = hex.EncodeToString(tx1.ExtendedBytes())
} else {
arcBodyTx = hex.EncodeToString(tx1.Bytes())
}
arcBody := api.POSTTransactionJSONRequestBody{
RawTx: arcBodyTx,
}
return arcBody
}
Loading

0 comments on commit 65bd1e8

Please sign in to comment.