-
Notifications
You must be signed in to change notification settings - Fork 176
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[payments] meterer structs and helpers #789
Conversation
core/meterer/offchain_store.go
Outdated
} | ||
|
||
update := map[string]types.AttributeValue{ | ||
"BinUsage": &types.AttributeValueMemberN{Value: strconv.FormatUint(uint64(size), 10)}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: size is already a uint64
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks! updated UpdateItemIncrement function to IncrementBy
that only takes in a key name and a value uint64
core/meterer/offchain_store.go
Outdated
"BinUsage": &types.AttributeValueMemberN{Value: strconv.FormatUint(uint64(size), 10)}, | ||
} | ||
|
||
fmt.Println("increment the item in a table", s.reservationTableName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove or convert to log?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed!
core/meterer/offchain_store.go
Outdated
} | ||
|
||
// Find all reservation bins for a given account | ||
func (s *OffchainStore) FindReservationBins(ctx context.Context, accountID string) ([]ReservationBin, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nope, this was for later exposing API to the user, but removed for now
core/meterer/types.go
Outdated
type BlobHeader struct { | ||
// Existing fields | ||
Commitment core.G1Point | ||
DataLength uint32 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: This should be the length in number of symbols.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a comment for this, though should I update the name to be something like NumSymbols
?
ae6e034
to
c55e7c0
Compare
f553c37
to
6ae70ef
Compare
common/aws/dynamodb/client.go
Outdated
@@ -38,7 +38,7 @@ var ( | |||
|
|||
type Item = map[string]types.AttributeValue | |||
type Key = map[string]types.AttributeValue | |||
type ExpresseionValues = map[string]types.AttributeValue | |||
type ExpresseionValues = map[string]types.AttributeValue // is this a typo? ExpressionValues? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lol yeah.. want to update this in a separate PR?
core/meterer/meterer.go
Outdated
TxnBroadcastTimeout time.Duration | ||
} | ||
|
||
// network parameters that should be published on-chain. We currently configure these params through disperser env vars. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: for any comments on a method/struct/field, start by the name of the method/struct/field. It will be recognized by godoc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated, thanks for the tip!
core/meterer/meterer.go
Outdated
// | ||
// If the payment is valid, the meterer will add the blob header to its state and return a success response to the disperser API server. | ||
// if any of the checks fail, the meterer will return a failure response to the disperser API server. | ||
var OnDemandQuorumNumbers = []uint8{0, 1} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These probably shouldn't be hardcoded
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think they should be published on-chain?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realized that this is a read function from transactor, so will do corresponding updates :)
core/meterer/types.go
Outdated
} | ||
|
||
// EIP712Signer handles EIP-712 signing operations | ||
type EIP712Signer struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This signature scheme will likely be shared for validating a request. Should this live outside meterer
package? Maybe somewhere like core/auth
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes sense, moved PaymentMetadata
to core/data.go
, and all the signing to core/auth
! If we enforce meterer
to handle everything PaymentMetadata
, I can move it back to meterer
package 🤔
core/meterer/offchain_store.go
Outdated
return nil, fmt.Errorf("table names cannot be empty") | ||
} | ||
|
||
err = CreateReservationTable(cfg, reservationTableName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tables should be created outside the application code (devops). We can check if the tables with corresponding names exist in the constructor and error out if they don't exist
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
makes sense, updated to use check and error instead of making db changes
core/meterer/util.go
Outdated
}, | ||
GlobalSecondaryIndexes: []types.GlobalSecondaryIndex{ | ||
{ | ||
IndexName: aws.String("AccountIDIndex"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this index? Looks like we already key by AccountID
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
During testing, I found that this IndexName was needed to enable QueryIndex
. I referenced the pattern like [here] with BlobStatus
key and StatusIndex
index (
IndexName: aws.String(statusIndexName), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah if you need to query by something other than the table's default keys, then building indexes on those attributes may help. However, looks like we can query by the table's default keys, in which case we can query from the table directly
core/meterer/util.go
Outdated
}, | ||
GlobalSecondaryIndexes: []types.GlobalSecondaryIndex{ | ||
{ | ||
IndexName: aws.String("AccountIDIndex"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
core/meterer/util.go
Outdated
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types" | ||
) | ||
|
||
func DummyCommitment() core.G1Point { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem used anywhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is used in later PRs but I've removed it since we are removing commitment from the Payment header
return *commitment | ||
} | ||
|
||
func CreateReservationTable(clientConfig commonaws.ClientConfig, tableName string) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like we can collapse these tables into a single table design. Wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 something like this?
My main consideration is the read/write performance based on the evenness of key distributions, and think it is clearer if different payment methods live in different tables, but I'm interested in learning the advantages of combining these into a single table
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a suggestion in the design doc. We can discuss it there
feb5543
to
a8a6ca9
Compare
49e938b
to
5b50c0e
Compare
af1d9fe
to
a6810c2
Compare
cc85c19
to
e7a8e3a
Compare
@@ -2,8 +2,10 @@ package dynamodb | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rebasing to master should hide these changes that have already been merged
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ahh just realized that this branch was configured to merge into the dynamo-update branch. updated the merge base so the changes should be hidden now
core/auth/payment_metadata.go
Outdated
{Name: "chainId", Type: "uint256"}, | ||
{Name: "verifyingContract", Type: "address"}, | ||
}, | ||
"PaymentMetadata": []apitypes.Type{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this depend on the structure of BlobHeader
in v2? (i.e. would signature over BlobHeader
be sufficient without one over PaymentMetadata
?)
Do we need this struct signed in both v1 & v2?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think payment metadata will depend on BlobHeader
v2 in which PaymentMetadata
includes BlobHeader
's hash, a field like BlobKey
.
This struct would always be signed, but I guess payments is currently disjointed from blob information. We could discuss whether it is okay to let payment be "blob-agnostic" in v1, and only check blob's dataLength against the paid amount?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In order to support both v1 and v2, what if we were to add a BlobKey
field here which is not populated in v1?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need signature over PaymentMetadata at all?
Disperser should validate the request independently i.e. by validating signature over the challenge parameter in v1, and by validating signature over blob key in v2.
Could downstream metering library assume the passed in payment metadata is correct?
@@ -470,3 +470,36 @@ func (cb Bundles) FromEncodedBundles(eb EncodedBundles) (Bundles, error) { | |||
} | |||
return c, nil | |||
} | |||
|
|||
// PaymentMetadata represents the header information for a blob | |||
type PaymentMetadata struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be independent of what BlobHeader looks like?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm we could add a field like blob key or blob pointer? this would mean we need to do blob lookup. With these current fields, we don't need the blob or blob header to do metering
core/meterer/meterer.go
Outdated
type Config struct { | ||
// for rate limiting 2^64 ~= 18 exabytes per second; 2^32 ~= 4GB/s | ||
// for payments 2^64 ~= 18M Eth; 2^32 ~= 4ETH | ||
GlobalBytesPerSecond uint64 // Global rate limit in bytes per second for on-demand payments |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: it's nicer to put comment for field description above the definition, starting with the name of the field
core/meterer/meterer.go
Outdated
ChainReadTimeout time.Duration // Timeout for reading payment state from chain | ||
} | ||
|
||
// disperser API server will receive requests from clients. these requests will be with a blobHeader with payments information (CumulativePayments, BinIndex, and Signature) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Meterer handles payment accounting across different accounts. Disperser API server receives requests from clients and each request contains a blob header....
core/meterer/meterer.go
Outdated
ChainState OnchainPayment | ||
OffchainStore OffchainStore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: brief description of what gets stored on which store and how they're used differently?
core/meterer/util.go
Outdated
}, | ||
GlobalSecondaryIndexes: []types.GlobalSecondaryIndex{ | ||
{ | ||
IndexName: aws.String("AccountIDIndex"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah if you need to query by something other than the table's default keys, then building indexes on those attributes may help. However, looks like we can query by the table's default keys, in which case we can query from the table directly
e7a8e3a
to
7c0c037
Compare
7c0c037
to
7854687
Compare
c8c1f3e
to
ac0c882
Compare
ac0c882
to
fab84e3
Compare
core/auth/payment_metadata_test.go
Outdated
t.Run("SignPaymentMetadata", func(t *testing.T) { | ||
signature, err := signer.SignPaymentMetadata(header, privateKey) | ||
require.NoError(t, err) | ||
assert.NotEmpty(t, signature) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing you can do is use a contract script like this to generate the same signature on chain and compare.
contract GenerateHashes is Script { |
core/auth/payment_metadata.go
Outdated
} | ||
|
||
// NewEIP712Signer creates a new EIP712Signer instance | ||
func NewEIP712Signer(chainID *big.Int, verifyingContract common.Address) *EIP712Signer { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the verifyingContract
ever have a function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, verifyingContract would only affect the output signature and the recovery
core/auth/payment_metadata.go
Outdated
{Name: "chainId", Type: "uint256"}, | ||
{Name: "verifyingContract", Type: "address"}, | ||
}, | ||
"PaymentMetadata": []apitypes.Type{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In order to support both v1 and v2, what if we were to add a BlobKey
field here which is not populated in v1?
core/auth/payment_metadata.go
Outdated
{Name: "accountID", Type: "string"}, | ||
{Name: "binIndex", Type: "uint32"}, | ||
{Name: "cumulativePayment", Type: "uint64"}, | ||
{Name: "dataLength", Type: "uint32"}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure the dataLength would be needed in v2 if we also have the blob key.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could I assume meterer will receive validated blob header which contains payment metadata and the quorum numbers and length? If so I could remove validateSignature
from the meterer process and make a new blobHeader struct?
core/auth/payment_metadata.go
Outdated
return signature, nil | ||
} | ||
|
||
func convertUint8SliceToMap(params []uint8) []string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
convertUint8SliceToStringSlice
?
c255424
to
aae5395
Compare
aae5395
to
4a50bf6
Compare
common/aws/dynamodb/client.go
Outdated
@@ -408,3 +409,17 @@ func (c *Client) readItems(ctx context.Context, tableName string, keys []Key) ([ | |||
|
|||
return items, nil | |||
} | |||
|
|||
// TableCheck checks if a table exists and can be described | |||
func (c *Client) TableCheck(ctx context.Context, name string) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: TableExists
?
core/data.go
Outdated
return crypto.Keccak256(data) | ||
} | ||
|
||
type TokenAmount uint64 // TODO: change to uint128 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should it be big.Int?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated I ended up deleting this type alias and just using big.Int directly
Config | ||
|
||
// ChainState reads on-chain payment state periodically and cache it in memory | ||
ChainState OnchainPayment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OnchainPayment
? ChainState
sounds like the ChainState
struct in chainio 😭
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we perhaps move it later?🫠 similar to replacing transactor with reader, I would prefer creating a separate PR after both of these are merged or at least chainio
gets merged??
// OnchainPaymentState is an interface for getting information about the current chain state for payments. | ||
type OnchainPayment interface { | ||
GetCurrentBlockNumber(ctx context.Context) (uint32, error) | ||
CurrentOnchainPaymentState(ctx context.Context, tx *eth.Transactor) (OnchainPaymentState, error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we use reader/writer from chainio
to replace transactor?
return *commitment | ||
} | ||
|
||
func CreateReservationTable(clientConfig commonaws.ClientConfig, tableName string) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a suggestion in the design doc. We can discuss it there
3545713
to
0d0dabf
Compare
0d0dabf
to
9d5663a
Compare
core/data.go
Outdated
} | ||
|
||
type OnDemandPayment struct { | ||
CumulativePayment big.Int // Total amount deposited by the user |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's common practice to use a pointer for big.Int, i.e. CumulativePayment *big.Int
, as most methods consume the pointer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sg, updated
Why are these changes needed?
adding structures used by payment meterer, with utility functions and unit tests
Checks