common

package
v0.0.0-...-e11926a Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 29, 2026 License: Apache-2.0 Imports: 48 Imported by: 43

Documentation

Index

Constants

View Source
const (
	// TxIDLenMin is the minimum length of a txID.
	TxIDLenMin = 32
	// AddressLength is the length of a normalized Wormhole address in bytes.
	AddressLength = 32

	// Wormhole supports arbitrary payloads due to the variance in transaction and block sizes between chains.
	// However, during serialization, payload lengths are limited by Go slice length constraints and violations
	// of these limits can cause panics.
	// (https://go.dev/src/runtime/slice.go)
	// This limit is chosen to be large enough to prevent such panics but it should comfortably handle all payloads.
	// If not, the limit can be increased.
	PayloadLenMax = 1024 * 1024 * 1024 * 10 // 10 GB

	// minMsgIdLen is the minimum length of a message ID. It is used to uniquely identify
	// messages in the case of a duplicate message ID and is stored in the database.
	MinMsgIdLen = len("1/0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16/0")
)
View Source
const (
	ReadinessEthSyncing readiness.Component = "ethSyncing"
	ReadinessIBCSyncing readiness.Component = "IBCSyncing"
)
View Source
const (
	GuardianKeyArmoredBlock = "WORMHOLE GUARDIAN PRIVATE KEY"
)
View Source
const MaxGuardianCount = 19

MaxGuardianCount specifies the maximum number of guardians supported by on-chain contracts.

Matching constants:

  • MAX_LEN_GUARDIAN_KEYS in Solana contract (limited by transaction size - 19 is the maximum amount possible)

The Eth and Terra contracts do not specify a maximum number and support more than that, but presumably, chain-specific transaction size limits will apply at some point (untested).

View Source
const MaxNodesPerGuardian = 30

MaxNodesPerGuardian specifies the maximum amount of nodes per guardian key that we'll accept whenever we maintain any per-guardian, per-node state.

There currently isn't any state clean up, so the value is on the high side to prevent accidentally reaching the limit due to operational mistakes.

View Source
const MaxSafeInputSize = 128 * 1024 * 1024 // 128MB (arbitrary)

MaxSafeInputSize defines the maximum safe size for untrusted input from `io` Readers. It should be configured so that it can comfortably contain all valid reads while providing a strict upper bound to prevent unlimited reads.

View Source
const MaxStateAge = 1 * time.Minute

MaxStateAge specified the maximum age of state entries in seconds. Expired entries are purged from the state by Cleanup().

View Source
const NumVariantsVerificationState = 6

NumVariantsVerificationState is the number of variants in the VerificationState enum. Used to validate deserialization.

Variables

View Source
var (
	ErrInvalidBinaryBool        = errors.New("invalid binary bool (neither 0x00 nor 0x01)")
	ErrInvalidVerificationState = errors.New("invalid verification state")
)
View Source
var (
	ErrBinaryWrite         = errors.New("failed to write binary data")
	ErrTxIDTooLong         = errors.New("field TxID too long")
	ErrTxIDTooShort        = errors.New("field TxID too short")
	ErrInvalidPayload      = errors.New("field payload too long")
	ErrDataTooShort        = errors.New("data too short")
	ErrTimestampTooShort   = errors.New("data too short for timestamp")
	ErrNonceTooShort       = errors.New("data too short for nonce")
	ErrSequenceTooShort    = errors.New("data too short for sequence")
	ErrConsistencyTooShort = errors.New("data too short for consistency level")
	ErrChainTooShort       = errors.New("data too short for emitter chain")
	ErrAddressTooShort     = errors.New("data too short for emitter address")
	ErrReobsTooShort       = errors.New("data too short for IsReobservation")
	ErrUnreliableTooShort  = errors.New("data too short for Unreliable")
	ErrVerStateTooShort    = errors.New("data too short for verification state")
	ErrPayloadLenTooShort  = errors.New("data too short for payload length")
	ErrPayloadTooShort     = errors.New("data too short for payload")
)
View Source
var (
	ScissorsErrorsCaught = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "scissor_errors_caught",
			Help: "Total number of unhandled errors caught",
		}, []string{"name"})
	ScissorsPanicsCaught = promauto.NewCounterVec(
		prometheus.CounterOpts{
			Name: "scissor_panics_caught",
			Help: "Total number of panics caught",
		}, []string{"name"})
)
View Source
var ErrChanFull = errors.New("channel is full")
View Source
var ErrInputTooLarge = errors.New("input data exceeds maximum allowed size")

Functions

func ConvertChainIdToReadinessSyncing

func ConvertChainIdToReadinessSyncing(chainID vaa.ChainID) (readiness.Component, error)

ConvertChainIdToReadinessSyncing maps a chain ID to a readiness syncing value. It returns an error if the chain ID is invalid.

func DecryptAESGCM

func DecryptAESGCM(data, key []byte) ([]byte, error)

func EncryptAESGCM

func EncryptAESGCM(plaintext, key []byte) ([]byte, error)

func GetOrCreateNodeKey

func GetOrCreateNodeKey(logger *zap.Logger, path string) (crypto.PrivKey, error)

func LoadArmoredKey

func LoadArmoredKey(filename string, blockType string, unsafeDevMode bool) (*ecdsa.PrivateKey, error)

LoadArmoredKey loads a serialized key from disk.

func LoadGuardianKey

func LoadGuardianKey(filename string, unsafeDevMode bool) (*ecdsa.PrivateKey, error)

LoadGuardianKey loads a serialized guardian key from disk.

func LockMemory

func LockMemory()

LockMemory locks current and future pages in memory to protect secret keys from being swapped out to disk. It's possible (and strongly recommended) to deploy Wormhole such that keys are only ever stored in memory and never touch the disk. This is a privileged operation and requires CAP_IPC_LOCK.

func MustConvertChainIdToReadinessSyncing

func MustConvertChainIdToReadinessSyncing(chainID vaa.ChainID) readiness.Component

MustConvertChainIdToReadinessSyncing maps a chain ID to a readiness syncing value. It panics if the chain ID is invalid so it should only be used during initialization.

func MustRegisterReadinessSyncing

func MustRegisterReadinessSyncing(chainID vaa.ChainID)

MustRegisterReadinessSyncing registers the specified chain for readiness syncing. It panics if the chain ID is invalid so it should only be used during initialization. TODO: Using vaa.ChainID is bad here because there can be multiple watchers for the same chainId, e.g. solana-finalized and solana-confirmed. This is currently handled as a special case for solana in node/node.go, but should really be fixed here.

func NewInstrumentedGRPCServer

func NewInstrumentedGRPCServer(logger *zap.Logger, rpcLogDetail GrpcLogDetail) *grpc.Server

func PostMsgWithTimestamp

func PostMsgWithTimestamp[T any](msg *T, c chan<- *MsgWithTimeStamp[T]) error

PostMsgWithTimestamp sends the message to the specified channel using the current timestamp. Returns ErrChanFull on error.

func PostObservationRequest

func PostObservationRequest(obsvReqSendC chan<- *gossipv1.ObservationRequest, req *gossipv1.ObservationRequest) error

func ReadFromChannelWithTimeout

func ReadFromChannelWithTimeout[T any](ctx context.Context, ch <-chan T, maxCount int) ([]T, error)

ReadFromChannelWithTimeout reads events from the channel until a timeout occurs or the max maxCount is reached.

func RunWithScissors

func RunWithScissors(ctx context.Context, errC chan error, name string, runnable supervisor.Runnable)

Start a go routine with recovering from any panic by sending an error to a error channel

func SafeRead

func SafeRead(r io.Reader) ([]byte, error)

SafeRead reads from r with a size limit to prevent memory exhaustion attacks. It returns an error if the input exceeds MaxSafeInputSize.

func SetRestrictiveUmask

func SetRestrictiveUmask()

SetRestrictiveUmask masks the group and world bits. This ensures that key material and sockets we create aren't accidentally group- or world-readable.

func StartRunnable

func StartRunnable(ctx context.Context, errC chan error, catchPanics bool, name string, runnable supervisor.Runnable)

StartRunnable starts a go routine with the ability to recover from errors by publishing them to an error channel. If catchPanics is true, it will also catch panics and publish the panic message to the error channel. If catchPanics is false, the panic will be propagated upward.

func ValidateURL

func ValidateURL(urlStr string, validSchemes []string) bool

func WrapWithScissors

func WrapWithScissors(runnable supervisor.Runnable, name string) supervisor.Runnable

func WriteArmoredKey

func WriteArmoredKey(key *ecdsa.PrivateKey, description string, filename string, blockType string, unsafe bool) error

WriteArmoredKey serializes a key and writes it to disk.

func WriteToChannelWithoutBlocking

func WriteToChannelWithoutBlocking[T any](channel chan<- T, evt T, label string)

WriteToChannelWithoutBlocking attempts to write the specified event to the specified channel. If the write would block, it increments the `channelWriteDrops` metric with the specified channel ID.

Types

type Environment

type Environment string
const (
	MainNet        Environment = "prod"
	UnsafeDevNet   Environment = "dev"  // local devnet; Keys are deterministic and many security controls are disabled
	TestNet        Environment = "test" // public testnet (needs to be reliable, but run with less Guardians and faster finality)
	GoTest         Environment = "unit-test"
	AccountantMock Environment = "accountant-mock" // Used for mocking accountant with a Wormchain connection
)

func ParseEnvironment

func ParseEnvironment(str string) (Environment, error)

ParseEnvironment parses a string into the corresponding Environment value, allowing various reasonable variations.

func (Environment) ToSDK

func (e Environment) ToSDK() sdk.Environment

ToSDK converts a common.Environment to sdk.Environment. This allows node code to use SDK functions that require sdk.Environment.

type ErrInputSize

type ErrInputSize struct {
	Msg  string
	Got  int
	Want int
}

ErrInputSize is returned when the input size is not the expected size during marshaling.

func (ErrInputSize) Error

func (e ErrInputSize) Error() string

type ErrUnexpectedEndOfRead

type ErrUnexpectedEndOfRead struct {
	// contains filtered or unexported fields
}

func (ErrUnexpectedEndOfRead) Error

func (e ErrUnexpectedEndOfRead) Error() string

type GrpcLogDetail

type GrpcLogDetail string
const (
	GrpcLogDetailNone    GrpcLogDetail = "none"
	GrpcLogDetailMinimal GrpcLogDetail = "minimal"
	GrpcLogDetailFull    GrpcLogDetail = "full"
)

type GuardianSet

type GuardianSet struct {
	// Guardian's public key hashes truncated by the ETH standard hashing mechanism (20 bytes).
	Keys []common.Address

	// On-chain set index
	Index uint32
	// contains filtered or unexported fields
}

func NewGuardianSet

func NewGuardianSet(keys []common.Address, index uint32) *GuardianSet

func (*GuardianSet) KeyIndex

func (g *GuardianSet) KeyIndex(addr common.Address) (int, bool)

KeyIndex returns a given address index from the guardian set. Returns (-1, false) if the address wasn't found and (addr, true) otherwise.

func (*GuardianSet) KeysAsHexStrings

func (g *GuardianSet) KeysAsHexStrings() []string

func (*GuardianSet) Quorum

func (gs *GuardianSet) Quorum() int

Quorum returns the current quorum value.

type GuardianSetState

type GuardianSetState struct {
	// contains filtered or unexported fields
}

func NewGuardianSetState

func NewGuardianSetState(guardianSetStateUpdateC chan *gossipv1.Heartbeat) *GuardianSetState

NewGuardianSetState returns a new GuardianSetState.

The provided channel will be pushed heartbeat updates as they are set, but be aware that the channel will block guardian set updates if full.

func (*GuardianSetState) Cleanup

func (st *GuardianSetState) Cleanup()

Cleanup removes expired entries from the state.

func (*GuardianSetState) Get

func (st *GuardianSetState) Get() *GuardianSet

func (*GuardianSetState) GetAll

func (st *GuardianSetState) GetAll() map[common.Address]map[peer.ID]*gossipv1.Heartbeat

GetAll returns all stored heartbeats.

func (*GuardianSetState) IsSubscribedToHeartbeats

func (st *GuardianSetState) IsSubscribedToHeartbeats() bool

IsSubscribedToHeartbeats returns true if the heartbeat update channel is set.

func (*GuardianSetState) LastHeartbeat

func (st *GuardianSetState) LastHeartbeat(addr common.Address) map[peer.ID]*gossipv1.Heartbeat

LastHeartbeat returns the most recent heartbeat message received for a given guardian node, or nil if none have been received.

func (*GuardianSetState) Set

func (st *GuardianSetState) Set(set *GuardianSet)

func (*GuardianSetState) SetHeartbeat

func (st *GuardianSetState) SetHeartbeat(addr common.Address, peerId peer.ID, hb *gossipv1.Heartbeat) error

SetHeartbeat stores a verified heartbeat observed by a given guardian.

type MessagePublication

type MessagePublication struct {
	TxID      []byte
	Timestamp time.Time

	Nonce            uint32
	Sequence         uint64
	ConsistencyLevel uint8
	EmitterChain     vaa.ChainID
	EmitterAddress   vaa.Address
	// NOTE: there is no upper bound on the size of the payload. Wormhole supports arbitrary payloads
	// due to the variance in transaction and block sizes between chains. However, during deserialization,
	// payload lengths are bounds-checked against [PayloadLenMax] to prevent makeslice panics from malformed input.
	Payload         []byte
	IsReobservation bool

	// Unreliable indicates if this message can be reobserved. If a message is considered unreliable it cannot be
	// reobserved.
	Unreliable bool
	// contains filtered or unexported fields
}

func UnmarshalMessagePublication deprecated

func UnmarshalMessagePublication(data []byte) (*MessagePublication, error)

Deprecated: UnmarshalMessagePublication deserializes a MessagePublication. This function does not unmarshal the Unreliable or verificationState fields. Use MessagePublication.UnmarshalBinary instead.

func (*MessagePublication) CreateDigest

func (msg *MessagePublication) CreateDigest() string

func (*MessagePublication) CreateVAA

func (msg *MessagePublication) CreateVAA(gsIndex uint32) *vaa.VAA

func (*MessagePublication) IsWTT

func (msg *MessagePublication) IsWTT(env Environment) bool

IsWTT checks if the MessagePublication represents a valid wrapped token transfer for a given environment. It verifies: 1. The payload is a transfer (payload type 1 or 3) via vaa.IsTransfer 2. The emitter is a known token bridge emitter for the specified environment

This method validates WTTs with respect to an environment's known token bridge emitters. For a context-free check that only verifies the payload type, use vaa.IsTransfer instead.

Returns false for test/mock environments (GoTest, AccountantMock) and if either check fails.

Note: This method uses the same validation logic as VAA.IsWTT.

func (*MessagePublication) Marshal deprecated

func (msg *MessagePublication) Marshal() ([]byte, error)

Deprecated: This function does not unmarshal the Unreliable or verificationState fields. Use MessagePublication.MarshalBinary instead.

func (*MessagePublication) MarshalBinary

func (msg *MessagePublication) MarshalBinary() ([]byte, error)

MarshalBinary implements the BinaryMarshaler interface for MessagePublication.

func (*MessagePublication) MarshalJSON

func (msg *MessagePublication) MarshalJSON() ([]byte, error)

The standard json Marshal / Unmarshal of time.Time gets confused between local and UTC time.

func (*MessagePublication) MessageID

func (msg *MessagePublication) MessageID() []byte

func (*MessagePublication) MessageIDString

func (msg *MessagePublication) MessageIDString() string

func (*MessagePublication) SetVerificationState

func (msg *MessagePublication) SetVerificationState(s VerificationState) error

SetVerificationState is the setter for verificationState. Returns an error if called in a way that likely indicates a programming mistake. This includes cases where: - an existing state would be overwritten by the NotVerified state - the argument is equal to the existing value

func (*MessagePublication) TxIDString

func (msg *MessagePublication) TxIDString() string

TxIDString returns a hex-encoded representation of the TxID field, prefixed with '0x'.

func (*MessagePublication) UnmarshalBinary

func (m *MessagePublication) UnmarshalBinary(data []byte) error

UnmarshalBinary implements the BinaryUnmarshaler interface for MessagePublication.

func (*MessagePublication) UnmarshalJSON

func (msg *MessagePublication) UnmarshalJSON(data []byte) error

func (*MessagePublication) VAAHash

func (msg *MessagePublication) VAAHash() string

VAAHash returns a hash corresponding to the fields of the Message Publication that are ultimately encoded in a VAA. This is a helper function used to uniquely identify a Message Publication.

func (*MessagePublication) VerificationState

func (msg *MessagePublication) VerificationState() VerificationState

func (*MessagePublication) ZapFields

func (msg *MessagePublication) ZapFields(fields ...zap.Field) []zap.Field

ZapFields takes some zap fields and appends zap fields related to the message. Example usage: `logger.Info("logging something with a message", msg.ZapFields(zap.Int("some_other_field", 100))...)“ TODO refactor the codebase to use this function instead of manually logging the message with inconsistent fields

type MsgWithTimeStamp

type MsgWithTimeStamp[T any] struct {
	Msg       *T
	Timestamp time.Time
}

MsgWithTimeStamp allows us to track the time of receipt of an event.

func CreateMsgWithTimestamp

func CreateMsgWithTimestamp[T any](msg *T) *MsgWithTimeStamp[T]

CreateMsgWithTimestamp creates a new MsgWithTimeStamp with the current time.

type PendingMessage

type PendingMessage struct {
	ReleaseTime time.Time
	Msg         MessagePublication
}

PendingMessage is a wrapper type around a MessagePublication that includes the time for which it should be released.

func (PendingMessage) Compare

func (p PendingMessage) Compare(other PendingMessage) int

func (*PendingMessage) MarshalBinary

func (p *PendingMessage) MarshalBinary() ([]byte, error)

MarshalBinary implements BinaryMarshaler for PendingMessage.

func (*PendingMessage) UnmarshalBinary

func (p *PendingMessage) UnmarshalBinary(data []byte) error

UnmarshalBinary implements BinaryUnmarshaler for PendingMessage.

type PendingMessageQueue

type PendingMessageQueue struct {
	// contains filtered or unexported fields
}

PendingMessageQueue is a thread-safe min-heap that sorts PendingMessage in descending order of Timestamp. It also prevents duplicate [MessagePublication]s from being added to the queue.

func NewPendingMessageQueue

func NewPendingMessageQueue() *PendingMessageQueue

func (*PendingMessageQueue) Contains

func (q *PendingMessageQueue) Contains(pMsg *PendingMessage) bool

Contains determines whether the queue contains a PendingMessage.

func (*PendingMessageQueue) FetchMessagePublication

func (q *PendingMessageQueue) FetchMessagePublication(msgID []byte) (msgPub *MessagePublication)

FetchMessagePublication returns a MessagePublication with the given ID if it exists in the queue, and nil otherwise.

func (*PendingMessageQueue) Len

func (q *PendingMessageQueue) Len() int

Len returns the number of elements in the queue. Returns 0 if the queue is nil.

func (*PendingMessageQueue) Peek

Peek returns the element at the top of the heap without removing it.

func (*PendingMessageQueue) Pop

Pop removes the last element from the heap and returns its value. Returns nil if the heap is empty or if the value is not a *PendingMessage.

func (*PendingMessageQueue) Push

func (q *PendingMessageQueue) Push(pMsg *PendingMessage)

Push adds an element to the heap. If the pending message's message ID is invalid, or if it already exists in the queue, nothing is added.

func (*PendingMessageQueue) RemoveItem

func (q *PendingMessageQueue) RemoveItem(msgID []byte) (*PendingMessage, error)

RemoveItem removes target MessagePublication with the message ID from the heap. Returns the element that was removed or nil if the item was not found. No error is returned if the item was not found.

type VerificationState

type VerificationState uint8

The `VerificationState` is the result of applying transfer verification to the transaction associated with the `MessagePublication`. While this could likely be extended to additional security controls in the future, it is only used for `txverifier` at present. Consequently, its status should be set to `NotVerified` or `NotApplicable` for all messages that aren't token transfers.

const (
	// The default state for a message. This can be used before verification occurs. If no verification is required, `NotApplicable` should be used instead.
	NotVerified VerificationState = iota
	// Represents a "known bad" status where a Message has been validated and the result indicates an erroneous or invalid message. The message should be discarded.
	Rejected
	// Represents a successful validation, neither confirmed to be good or bad, but unusual.
	Anomalous
	// Represents a "known good" status where a Message has been validated and the result is good. The message should be processed normally.
	Valid
	// Indicates that no verification is necessary.
	NotApplicable
	// The message could not complete the verification process.
	CouldNotVerify
)

func (VerificationState) String

func (v VerificationState) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL