-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #327 from ava-labs/gstuart/api-relay
API endpoint for manually relaying warp message
- Loading branch information
Showing
20 changed files
with
1,032 additions
and
795 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package api | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
|
||
"github.com/alexliesenfeld/health" | ||
"github.com/ava-labs/avalanchego/ids" | ||
"github.com/ava-labs/avalanchego/utils/logging" | ||
"go.uber.org/atomic" | ||
"go.uber.org/zap" | ||
) | ||
|
||
const HealthAPIPath = "/health" | ||
|
||
func HandleHealthCheck(logger logging.Logger, relayerHealth map[ids.ID]*atomic.Bool) { | ||
http.Handle(HealthAPIPath, healthCheckHandler(logger, relayerHealth)) | ||
} | ||
|
||
func healthCheckHandler(logger logging.Logger, relayerHealth map[ids.ID]*atomic.Bool) http.Handler { | ||
return health.NewHandler(health.NewChecker( | ||
health.WithCheck(health.Check{ | ||
Name: "relayers-all", | ||
Check: func(context.Context) error { | ||
// Store the IDs as the cb58 encoding | ||
var unhealthyRelayers []string | ||
for id, health := range relayerHealth { | ||
if !health.Load() { | ||
unhealthyRelayers = append(unhealthyRelayers, id.String()) | ||
} | ||
} | ||
|
||
if len(unhealthyRelayers) > 0 { | ||
logger.Fatal("Relayers are unhealthy for blockchains", zap.Strings("blockchains", unhealthyRelayers)) | ||
return fmt.Errorf("relayers are unhealthy for blockchains %v", unhealthyRelayers) | ||
} | ||
return nil | ||
}, | ||
}), | ||
)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
package api | ||
|
||
import ( | ||
"encoding/json" | ||
"math/big" | ||
"net/http" | ||
|
||
"github.com/ava-labs/avalanchego/ids" | ||
"github.com/ava-labs/avalanchego/utils/logging" | ||
"github.com/ava-labs/awm-relayer/relayer" | ||
"github.com/ava-labs/awm-relayer/types" | ||
relayerTypes "github.com/ava-labs/awm-relayer/types" | ||
"github.com/ethereum/go-ethereum/common" | ||
"go.uber.org/zap" | ||
) | ||
|
||
const ( | ||
RelayAPIPath = "/relay" | ||
RelayMessageAPIPath = RelayAPIPath + "/message" | ||
) | ||
|
||
type RelayMessageRequest struct { | ||
// Required. cb58 encoding of the source blockchain ID for the message | ||
BlockchainID string `json:"blockchain-id"` | ||
// Required. cb58 encoding of the warp message ID | ||
MessageID string `json:"message-id"` | ||
// Required. Block number that the message was sent in | ||
BlockNum uint64 `json:"block-num"` | ||
} | ||
|
||
type RelayMessageResponse struct { | ||
// hex encoding of the transaction hash containing the processed message | ||
TransactionHash string `json:"transaction-hash"` | ||
} | ||
|
||
// Defines a manual warp message to be sent from the relayer through the API. | ||
type ManualWarpMessageRequest struct { | ||
UnsignedMessageBytes []byte `json:"unsigned-message-bytes"` | ||
SourceAddress string `json:"source-address"` | ||
} | ||
|
||
func HandleRelayMessage(logger logging.Logger, messageCoordinator *relayer.MessageCoordinator) { | ||
http.Handle(RelayAPIPath, relayAPIHandler(logger, messageCoordinator)) | ||
} | ||
|
||
func HandleRelay(logger logging.Logger, messageCoordinator *relayer.MessageCoordinator) { | ||
http.Handle(RelayMessageAPIPath, relayMessageAPIHandler(logger, messageCoordinator)) | ||
} | ||
|
||
func relayMessageAPIHandler(logger logging.Logger, messageCoordinator *relayer.MessageCoordinator) http.Handler { | ||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
var req ManualWarpMessageRequest | ||
err := json.NewDecoder(r.Body).Decode(&req) | ||
if err != nil { | ||
logger.Warn("Could not decode request body") | ||
http.Error(w, err.Error(), http.StatusBadRequest) | ||
return | ||
} | ||
|
||
unsignedMessage, err := types.UnpackWarpMessage(req.UnsignedMessageBytes) | ||
if err != nil { | ||
logger.Warn("Error unpacking warp message", zap.Error(err)) | ||
http.Error(w, err.Error(), http.StatusBadRequest) | ||
return | ||
} | ||
|
||
warpMessageInfo := &relayerTypes.WarpMessageInfo{ | ||
SourceAddress: common.HexToAddress(req.SourceAddress), | ||
UnsignedMessage: unsignedMessage, | ||
} | ||
|
||
txHash, err := messageCoordinator.ProcessWarpMessage(warpMessageInfo) | ||
if err != nil { | ||
logger.Error("Error processing message", zap.Error(err)) | ||
http.Error(w, "error processing message: "+err.Error(), http.StatusInternalServerError) | ||
return | ||
} | ||
|
||
resp, err := json.Marshal( | ||
RelayMessageResponse{ | ||
TransactionHash: txHash.Hex(), | ||
}, | ||
) | ||
if err != nil { | ||
logger.Error("Error marshaling response", zap.Error(err)) | ||
http.Error(w, "error marshaling response: "+err.Error(), http.StatusInternalServerError) | ||
return | ||
} | ||
|
||
_, err = w.Write(resp) | ||
if err != nil { | ||
logger.Error("Error writing response", zap.Error(err)) | ||
} | ||
}) | ||
} | ||
|
||
func relayAPIHandler(logger logging.Logger, messageCoordinator *relayer.MessageCoordinator) http.Handler { | ||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
var req RelayMessageRequest | ||
err := json.NewDecoder(r.Body).Decode(&req) | ||
if err != nil { | ||
logger.Warn("Could not decode request body") | ||
http.Error(w, err.Error(), http.StatusBadRequest) | ||
return | ||
} | ||
|
||
blockchainID, err := ids.FromString(req.BlockchainID) | ||
if err != nil { | ||
logger.Warn("Invalid blockchainID", zap.String("blockchainID", req.BlockchainID)) | ||
http.Error(w, "invalid blockchainID: "+err.Error(), http.StatusBadRequest) | ||
return | ||
} | ||
messageID, err := ids.FromString(req.MessageID) | ||
if err != nil { | ||
logger.Warn("Invalid messageID", zap.String("messageID", req.MessageID)) | ||
http.Error(w, "invalid messageID: "+err.Error(), http.StatusBadRequest) | ||
return | ||
} | ||
|
||
txHash, err := messageCoordinator.ProcessMessageID(blockchainID, messageID, new(big.Int).SetUint64(req.BlockNum)) | ||
if err != nil { | ||
logger.Error("Error processing message", zap.Error(err)) | ||
http.Error(w, "error processing message: "+err.Error(), http.StatusInternalServerError) | ||
return | ||
} | ||
|
||
resp, err := json.Marshal( | ||
RelayMessageResponse{ | ||
TransactionHash: txHash.Hex(), | ||
}, | ||
) | ||
if err != nil { | ||
logger.Error("Error marshalling response", zap.Error(err)) | ||
http.Error(w, "error marshalling response: "+err.Error(), http.StatusInternalServerError) | ||
return | ||
} | ||
|
||
_, err = w.Write(resp) | ||
if err != nil { | ||
logger.Error("Error writing response", zap.Error(err)) | ||
} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.