g/wei math->primitives, some new helpers (#14026)

Co-authored-by: Kasey Kirkham <kasey@users.noreply.github.com>
This commit is contained in:
kasey
2024-05-20 10:40:46 -05:00
committed by GitHub
parent 8a12b78684
commit 9befb6bd06
58 changed files with 398 additions and 358 deletions

View File

@@ -24,7 +24,6 @@ go_library(
"//container/trie:go_default_library",
"//encoding/bytesutil:go_default_library",
"//encoding/ssz:go_default_library",
"//math:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/validator-client:go_default_library",

View File

@@ -9,9 +9,9 @@ import (
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
consensus_types "github.com/prysmaticlabs/prysm/v5/consensus-types"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/v5/encoding/ssz"
"github.com/prysmaticlabs/prysm/v5/math"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
"google.golang.org/protobuf/proto"
)
@@ -24,7 +24,7 @@ type executionPayload struct {
}
// NewWrappedExecutionData creates an appropriate execution payload wrapper based on the incoming type.
func NewWrappedExecutionData(v proto.Message, weiValue math.Wei) (interfaces.ExecutionData, error) {
func NewWrappedExecutionData(v proto.Message, weiValue primitives.Wei) (interfaces.ExecutionData, error) {
if weiValue == nil {
weiValue = new(big.Int).SetInt64(0)
}
@@ -194,7 +194,7 @@ func (e executionPayload) ExcessBlobGas() (uint64, error) {
}
// ValueInWei --
func (executionPayload) ValueInWei() (math.Wei, error) {
func (executionPayload) ValueInWei() (primitives.Wei, error) {
return nil, consensus_types.ErrUnsupportedField
}
@@ -362,7 +362,7 @@ func (e executionPayloadHeader) ExcessBlobGas() (uint64, error) {
}
// ValueInWei --
func (executionPayloadHeader) ValueInWei() (math.Wei, error) {
func (executionPayloadHeader) ValueInWei() (primitives.Wei, error) {
return nil, consensus_types.ErrUnsupportedField
}
@@ -404,15 +404,15 @@ func PayloadToHeader(payload interfaces.ExecutionData) (*enginev1.ExecutionPaylo
// blocks for future forks can also be applied across Prysm without issues.
type executionPayloadCapella struct {
p *enginev1.ExecutionPayloadCapella
weiValue math.Wei
weiValue primitives.Wei
gweiValue uint64
}
var _ interfaces.ExecutionData = &executionPayloadCapella{}
// WrappedExecutionPayloadCapella is a constructor which wraps a protobuf execution payload into an interface.
func WrappedExecutionPayloadCapella(p *enginev1.ExecutionPayloadCapella, value math.Wei) (interfaces.ExecutionData, error) {
w := executionPayloadCapella{p: p, weiValue: value, gweiValue: uint64(math.WeiToGwei(value))}
func WrappedExecutionPayloadCapella(p *enginev1.ExecutionPayloadCapella, value primitives.Wei) (interfaces.ExecutionData, error) {
w := executionPayloadCapella{p: p, weiValue: value, gweiValue: uint64(primitives.WeiToGwei(value))}
if w.IsNil() {
return nil, consensus_types.ErrNilObjectWrapped
}
@@ -560,7 +560,7 @@ func (e executionPayloadCapella) ExcessBlobGas() (uint64, error) {
}
// ValueInWei --
func (e executionPayloadCapella) ValueInWei() (math.Wei, error) {
func (e executionPayloadCapella) ValueInWei() (primitives.Wei, error) {
return e.weiValue, nil
}
@@ -574,15 +574,15 @@ func (e executionPayloadCapella) ValueInGwei() (uint64, error) {
// blocks for future forks can also be applied across Prysm without issues.
type executionPayloadHeaderCapella struct {
p *enginev1.ExecutionPayloadHeaderCapella
weiValue math.Wei
weiValue primitives.Wei
gweiValue uint64
}
var _ interfaces.ExecutionData = &executionPayloadHeaderCapella{}
// WrappedExecutionPayloadHeaderCapella is a constructor which wraps a protobuf execution header into an interface.
func WrappedExecutionPayloadHeaderCapella(p *enginev1.ExecutionPayloadHeaderCapella, value math.Wei) (interfaces.ExecutionData, error) {
w := executionPayloadHeaderCapella{p: p, weiValue: value, gweiValue: uint64(math.WeiToGwei(value))}
func WrappedExecutionPayloadHeaderCapella(p *enginev1.ExecutionPayloadHeaderCapella, value primitives.Wei) (interfaces.ExecutionData, error) {
w := executionPayloadHeaderCapella{p: p, weiValue: value, gweiValue: uint64(primitives.WeiToGwei(value))}
if w.IsNil() {
return nil, consensus_types.ErrNilObjectWrapped
}
@@ -730,7 +730,7 @@ func (e executionPayloadHeaderCapella) ExcessBlobGas() (uint64, error) {
}
// ValueInWei --
func (e executionPayloadHeaderCapella) ValueInWei() (math.Wei, error) {
func (e executionPayloadHeaderCapella) ValueInWei() (primitives.Wei, error) {
return e.weiValue, nil
}
@@ -966,15 +966,15 @@ func IsEmptyExecutionData(data interfaces.ExecutionData) (bool, error) {
// blocks for future forks can also be applied across Prysm without issues.
type executionPayloadHeaderDeneb struct {
p *enginev1.ExecutionPayloadHeaderDeneb
weiValue math.Wei
weiValue primitives.Wei
gweiValue uint64
}
var _ interfaces.ExecutionData = &executionPayloadHeaderDeneb{}
// WrappedExecutionPayloadHeaderDeneb is a constructor which wraps a protobuf execution header into an interface.
func WrappedExecutionPayloadHeaderDeneb(p *enginev1.ExecutionPayloadHeaderDeneb, value math.Wei) (interfaces.ExecutionData, error) {
w := executionPayloadHeaderDeneb{p: p, weiValue: value, gweiValue: uint64(math.WeiToGwei(value))}
func WrappedExecutionPayloadHeaderDeneb(p *enginev1.ExecutionPayloadHeaderDeneb, value primitives.Wei) (interfaces.ExecutionData, error) {
w := executionPayloadHeaderDeneb{p: p, weiValue: value, gweiValue: uint64(primitives.WeiToGwei(value))}
if w.IsNil() {
return nil, consensus_types.ErrNilObjectWrapped
}
@@ -1117,7 +1117,7 @@ func (e executionPayloadHeaderDeneb) ExcessBlobGas() (uint64, error) {
}
// ValueInWei --
func (e executionPayloadHeaderDeneb) ValueInWei() (math.Wei, error) {
func (e executionPayloadHeaderDeneb) ValueInWei() (primitives.Wei, error) {
return e.weiValue, nil
}
@@ -1136,15 +1136,15 @@ func (e executionPayloadHeaderDeneb) IsBlinded() bool {
// blocks for future forks can also be applied across Prysm without issues.
type executionPayloadDeneb struct {
p *enginev1.ExecutionPayloadDeneb
weiValue math.Wei
weiValue primitives.Wei
gweiValue uint64
}
var _ interfaces.ExecutionData = &executionPayloadDeneb{}
// WrappedExecutionPayloadDeneb is a constructor which wraps a protobuf execution payload into an interface.
func WrappedExecutionPayloadDeneb(p *enginev1.ExecutionPayloadDeneb, value math.Wei) (interfaces.ExecutionData, error) {
w := executionPayloadDeneb{p: p, weiValue: value, gweiValue: uint64(math.WeiToGwei(value))}
func WrappedExecutionPayloadDeneb(p *enginev1.ExecutionPayloadDeneb, value primitives.Wei) (interfaces.ExecutionData, error) {
w := executionPayloadDeneb{p: p, weiValue: value, gweiValue: uint64(primitives.WeiToGwei(value))}
if w.IsNil() {
return nil, consensus_types.ErrNilObjectWrapped
}
@@ -1285,7 +1285,7 @@ func (e executionPayloadDeneb) ExcessBlobGas() (uint64, error) {
}
// ValueInWei --
func (e executionPayloadDeneb) ValueInWei() (math.Wei, error) {
func (e executionPayloadDeneb) ValueInWei() (primitives.Wei, error) {
return e.weiValue, nil
}
@@ -1304,7 +1304,7 @@ func (e executionPayloadDeneb) IsBlinded() bool {
// blocks for future forks can also be applied across Prysm without issues.
type executionPayloadHeaderElectra struct {
p *enginev1.ExecutionPayloadHeaderElectra
weiValue math.Wei
weiValue primitives.Wei
gweiValue uint64
}
@@ -1312,8 +1312,8 @@ var _ interfaces.ExecutionData = &executionPayloadElectra{}
var _ interfaces.ExecutionDataElectra = &executionPayloadElectra{}
// WrappedExecutionPayloadHeaderElectra is a constructor which wraps a protobuf execution header into an interface.
func WrappedExecutionPayloadHeaderElectra(p *enginev1.ExecutionPayloadHeaderElectra, value math.Wei) (interfaces.ExecutionData, error) {
w := executionPayloadHeaderElectra{p: p, weiValue: value, gweiValue: uint64(math.WeiToGwei(value))}
func WrappedExecutionPayloadHeaderElectra(p *enginev1.ExecutionPayloadHeaderElectra, value primitives.Wei) (interfaces.ExecutionData, error) {
w := executionPayloadHeaderElectra{p: p, weiValue: value, gweiValue: uint64(primitives.WeiToGwei(value))}
if w.IsNil() {
return nil, consensus_types.ErrNilObjectWrapped
}
@@ -1456,7 +1456,7 @@ func (e executionPayloadHeaderElectra) ExcessBlobGas() (uint64, error) {
}
// ValueInWei --
func (e executionPayloadHeaderElectra) ValueInWei() (math.Wei, error) {
func (e executionPayloadHeaderElectra) ValueInWei() (primitives.Wei, error) {
return e.weiValue, nil
}
@@ -1485,13 +1485,13 @@ func (e executionPayloadHeaderElectra) IsBlinded() bool {
// blocks for future forks can also be applied across Prysm without issues.
type executionPayloadElectra struct {
p *enginev1.ExecutionPayloadElectra
weiValue math.Wei
weiValue primitives.Wei
gweiValue uint64
}
// WrappedExecutionPayloadElectra is a constructor which wraps a protobuf execution payload into an interface.
func WrappedExecutionPayloadElectra(p *enginev1.ExecutionPayloadElectra, value math.Wei) (interfaces.ExecutionData, error) {
w := executionPayloadElectra{p: p, weiValue: value, gweiValue: uint64(math.WeiToGwei(value))}
func WrappedExecutionPayloadElectra(p *enginev1.ExecutionPayloadElectra, value primitives.Wei) (interfaces.ExecutionData, error) {
w := executionPayloadElectra{p: p, weiValue: value, gweiValue: uint64(primitives.WeiToGwei(value))}
if w.IsNil() {
return nil, consensus_types.ErrNilObjectWrapped
}
@@ -1635,7 +1635,7 @@ func (e executionPayloadElectra) ExcessBlobGas() (uint64, error) {
}
// ValueInWei --
func (e executionPayloadElectra) ValueInWei() (math.Wei, error) {
func (e executionPayloadElectra) ValueInWei() (primitives.Wei, error) {
return e.weiValue, nil
}
@@ -1660,14 +1660,14 @@ func (e executionPayloadElectra) IsBlinded() bool {
}
// PayloadValueToWei returns a Wei value given the payload's value
func PayloadValueToWei(value []byte) math.Wei {
func PayloadValueToWei(value []byte) primitives.Wei {
// We have to convert big endian to little endian because the value is coming from the execution layer.
return big.NewInt(0).SetBytes(bytesutil.ReverseByteOrder(value))
}
// PayloadValueToGwei returns a Gwei value given the payload's value
func PayloadValueToGwei(value []byte) math.Gwei {
func PayloadValueToGwei(value []byte) primitives.Gwei {
// We have to convert big endian to little endian because the value is coming from the execution layer.
v := big.NewInt(0).SetBytes(bytesutil.ReverseByteOrder(value))
return math.WeiToGwei(v)
return primitives.WeiToGwei(v)
}

View File

@@ -10,7 +10,6 @@ import (
consensus_types "github.com/prysmaticlabs/prysm/v5/consensus-types"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/math"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
validatorpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/validator-client"
@@ -329,7 +328,7 @@ func (b *SignedBeaconBlock) IsBlinded() bool {
}
// ValueInWei metadata on the payload value returned by the builder.
func (b *SignedBeaconBlock) ValueInWei() math.Wei {
func (b *SignedBeaconBlock) ValueInWei() primitives.Wei {
exec, err := b.block.body.Execution()
if err != nil {
if !errors.Is(err, consensus_types.ErrUnsupportedField) {

View File

@@ -14,7 +14,6 @@ go_library(
deps = [
"//config/fieldparams:go_default_library",
"//consensus-types/primitives:go_default_library",
"//math:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/validator-client:go_default_library",

View File

@@ -6,7 +6,6 @@ import (
"github.com/prysmaticlabs/go-bitfield"
field_params "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/math"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
validatorpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/validator-client"
@@ -29,7 +28,7 @@ type ReadOnlySignedBeaconBlock interface {
ssz.Unmarshaler
Version() int
IsBlinded() bool
ValueInWei() math.Wei
ValueInWei() primitives.Wei
ValueInGwei() uint64
Header() (*ethpb.SignedBeaconBlockHeader, error)
}
@@ -130,7 +129,7 @@ type ExecutionData interface {
TransactionsRoot() ([]byte, error)
Withdrawals() ([]*enginev1.Withdrawal, error)
WithdrawalsRoot() ([]byte, error)
ValueInWei() (math.Wei, error)
ValueInWei() (primitives.Wei, error)
ValueInGwei() (uint64, error)
}

View File

@@ -9,7 +9,6 @@ go_library(
"//config/fieldparams:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//math:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/validator-client:go_default_library",
"@com_github_prysmaticlabs_fastssz//:go_default_library",

View File

@@ -5,7 +5,6 @@ import (
field_params "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/math"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
validatorpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/validator-client"
"google.golang.org/protobuf/proto"
@@ -75,7 +74,7 @@ func (SignedBeaconBlock) Header() (*eth.SignedBeaconBlockHeader, error) {
panic("implement me")
}
func (SignedBeaconBlock) ValueInWei() math.Wei {
func (SignedBeaconBlock) ValueInWei() primitives.Wei {
panic("implement me")
}

View File

@@ -13,6 +13,7 @@ go_library(
"sszbytes.go",
"sszuint64.go",
"validator.go",
"wei.go",
],
importpath = "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives",
visibility = ["//visibility:public"],
@@ -32,6 +33,7 @@ go_test(
"sszbytes_test.go",
"sszuint64_test.go",
"validator_test.go",
"wei_test.go",
],
embed = [":go_default_library"],
deps = [

View File

@@ -0,0 +1,93 @@
package primitives
import (
"fmt"
"math/big"
"slices"
fssz "github.com/prysmaticlabs/fastssz"
)
// ZeroWei is a non-nil zero value for primitives.Wei
var ZeroWei Wei = big.NewInt(0)
// Wei is the smallest unit of Ether, represented as a pointer to a bigInt.
type Wei *big.Int
// Gwei is a denomination of 1e9 Wei represented as an uint64.
type Gwei uint64
var _ fssz.HashRoot = (Gwei)(0)
var _ fssz.Marshaler = (*Gwei)(nil)
var _ fssz.Unmarshaler = (*Gwei)(nil)
// HashTreeRoot --
func (g Gwei) HashTreeRoot() ([32]byte, error) {
return fssz.HashWithDefaultHasher(g)
}
// HashTreeRootWith --
func (g Gwei) HashTreeRootWith(hh *fssz.Hasher) error {
hh.PutUint64(uint64(g))
return nil
}
// UnmarshalSSZ --
func (g *Gwei) UnmarshalSSZ(buf []byte) error {
if len(buf) != g.SizeSSZ() {
return fmt.Errorf("expected buffer of length %d received %d", g.SizeSSZ(), len(buf))
}
*g = Gwei(fssz.UnmarshallUint64(buf))
return nil
}
// MarshalSSZTo --
func (g *Gwei) MarshalSSZTo(dst []byte) ([]byte, error) {
marshalled, err := g.MarshalSSZ()
if err != nil {
return nil, err
}
return append(dst, marshalled...), nil
}
// MarshalSSZ --
func (g *Gwei) MarshalSSZ() ([]byte, error) {
marshalled := fssz.MarshalUint64([]byte{}, uint64(*g))
return marshalled, nil
}
// SizeSSZ --
func (g *Gwei) SizeSSZ() int {
return 8
}
// WeiToBigInt is a convenience method to cast a wei back to a big int
func WeiToBigInt(w Wei) *big.Int {
return w
}
// Uint64ToWei creates a new Wei (aka big.Int) representing the given uint64 value.
func Uint64ToWei(v uint64) Wei {
return big.NewInt(0).SetUint64(v)
}
// BigEndianBytesToWei returns a Wei value given a big-endian binary representation (eg engine api payload bids).
func BigEndianBytesToWei(value []byte) Wei {
v := make([]byte, len(value))
copy(v, value)
slices.Reverse(v)
// We have to convert big endian to little endian because the value is coming from the execution layer.
return big.NewInt(0).SetBytes(v)
}
// WeiToGwei converts big int wei to uint64 gwei.
// The input `v` is copied before being modified.
func WeiToGwei(v Wei) Gwei {
if v == nil {
return 0
}
gweiPerEth := big.NewInt(1e9)
copied := big.NewInt(0).Set(v)
copied.Div(copied, gweiPerEth)
return Gwei(copied.Uint64())
}

View File

@@ -0,0 +1,41 @@
package primitives_test
import (
"math"
"math/big"
"testing"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/testing/require"
)
func TestWeiStringer(t *testing.T) {
require.Equal(t, "0", primitives.WeiToBigInt(primitives.ZeroWei).String())
require.Equal(t, "1234", primitives.WeiToBigInt(primitives.Uint64ToWei(1234)).String())
require.Equal(t, "18446744073709551615", primitives.WeiToBigInt(primitives.Uint64ToWei(math.MaxUint64)).String())
}
func TestWeiToGwei(t *testing.T) {
tests := []struct {
v *big.Int
want primitives.Gwei
}{
{big.NewInt(1e9 - 1), 0},
{big.NewInt(1e9), 1},
{big.NewInt(1e10), 10},
{big.NewInt(239489233849348394), 239489233},
}
for _, tt := range tests {
if got := primitives.WeiToGwei(tt.v); got != tt.want {
t.Errorf("WeiToGwei() = %v, want %v", got, tt.want)
}
}
}
func TestWeiToGwei_CopyOk(t *testing.T) {
v := big.NewInt(1e9)
got := primitives.WeiToGwei(v)
require.Equal(t, primitives.Gwei(1), got)
require.Equal(t, big.NewInt(1e9).Uint64(), v.Uint64())
}