Skip to content
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

chore: upstream stf to main #20286

Merged
merged 20 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/v2-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: v2 core Tests
on:
pull_request:
merge_group:
push:
branches:
- main

permissions:
contents: read

concurrency:
group: ci-${{ github.ref }}-v2-tests
cancel-in-progress: true

jobs:
tests:
tac0turtle marked this conversation as resolved.
Show resolved Hide resolved
runs-on: ubuntu-latest
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.22"
check-latest: true
cache: true
cache-dependency-path: go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
server/v2/stf/**/*.go
server/v2/stf/go.mod
server/v2/stf/go.sum
- name: test & coverage report creation
if: env.GIT_DIFF
run: |
cd server/v2/stf && go test -mod=readonly -race -timeout 30m -covermode=atomic -tags='ledger test_ledger_mock'
66 changes: 66 additions & 0 deletions core/app/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package app

import (
"time"

appmodulev2 "cosmossdk.io/core/appmodule/v2"
"cosmossdk.io/core/event"
"cosmossdk.io/core/transaction"
)

type QueryRequest struct {
Height int64
Path string
Data []byte
}

type QueryResponse struct {
Height int64
Value []byte
}

type BlockRequest[T any] struct {
Height uint64
Time time.Time
Hash []byte
ChainId string
AppHash []byte
Txs []T
ConsensusMessages []transaction.Type
}

type BlockResponse struct {
Apphash []byte
ConsensusMessagesResponse []transaction.Type
ValidatorUpdates []appmodulev2.ValidatorUpdate
PreBlockEvents []event.Event
BeginBlockEvents []event.Event
TxResults []TxResult
EndBlockEvents []event.Event
}

type RequestInitChain struct {
Time time.Time
ChainId string
Validators []appmodulev2.ValidatorUpdate
AppStateBytes []byte
InitialHeight int64
}

type ResponseInitChain struct {
Validators []appmodulev2.ValidatorUpdate
AppHash []byte
}

type TxResult struct {
Events []event.Event
Resp []transaction.Type
Error error
Code uint32
Data []byte
Log string
Info string
GasWanted uint64
GasUsed uint64
Codespace string
}
21 changes: 21 additions & 0 deletions core/app/codec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package app

import (
"github.com/cosmos/gogoproto/jsonpb"
gogoproto "github.com/cosmos/gogoproto/proto"
)

// MsgInterfaceProtoName defines the protobuf name of the cosmos Msg interface
const MsgInterfaceProtoName = "cosmos.base.v1beta1.Msg"

type ProtoCodec interface {
Marshal(v gogoproto.Message) ([]byte, error)
Unmarshal(data []byte, v gogoproto.Message) error
Name() string
}

type InterfaceRegistry interface {
jsonpb.AnyResolver
ListImplementations(ifaceTypeURL string) []string
ListAllInterfaces() []string
}
6 changes: 6 additions & 0 deletions core/app/identity.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package app

var (
RuntimeIdentity = []byte("runtime")
ConsensusIdentity = []byte("consensus")
)
14 changes: 14 additions & 0 deletions core/context/context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package appmodule

// ExecMode defines the execution mode which can be set on a Context.
type ExecMode uint8

// All possible execution modes.
const (
ExecModeCheck ExecMode = iota
Copy link
Contributor

@alpe alpe May 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

personal preference: reserve 0 for undefined so that you can check for that if needed and not default to "ExecModeCheck"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was to keep inline with existing types. will check if its safe to break

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, let's please not break, we try to keep them in sync (so we can just cast them). See

// All possible execution modes.
// For backwards compatibility and easier casting, the exec mode values must be the same as in cosmos/cosmos-sdk/types package.
const (
ExecModeCheck ExecMode = iota
ExecModeReCheck
ExecModeSimulate
_
_
_
_
ExecModeFinalize
)
for instance.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did that same as context, one less sdk dep throughout for baseapp

ExecModeReCheck
ExecModePrepareProposal
ExecModeProcessProposal
ExecModeSimulate
ExecModeFinalize
)
4 changes: 2 additions & 2 deletions core/gas/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ type Service interface {

// Meter represents a gas meter for modules consumption
type Meter interface {
Consume(amount Gas, descriptor string)
Refund(amount Gas, descriptor string)
Consume(amount Gas, descriptor string) error
tac0turtle marked this conversation as resolved.
Show resolved Hide resolved
Refund(amount Gas, descriptor string) error
Remaining() Gas
Limit() Gas
}
Expand Down
75 changes: 74 additions & 1 deletion core/header/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package header

import (
"context"
"crypto/sha256"
"encoding/binary"
"errors"
"fmt"
"time"
)

Expand All @@ -15,6 +19,75 @@ type Info struct {
Height int64 // Height returns the height of the block
Hash []byte // Hash returns the hash of the block header
Time time.Time // Time returns the time of the block
ChainID string // ChainId returns the chain ID of the block
AppHash []byte // AppHash used in the current block header
ChainID string // ChainId returns the chain ID of the block
}

const hashSize = sha256.Size

// Bytes encodes the Info struct into a byte slice using little-endian encoding
func (i *Info) Bytes() ([]byte, error) {
buf := make([]byte, 0)

// Encode Height
heightBytes := make([]byte, 8)
binary.LittleEndian.PutUint64(heightBytes, uint64(i.Height))
buf = append(buf, heightBytes...)

// Encode Hash
if len(i.Hash) != hashSize {
return nil, errors.New("invalid hash size")
}
buf = append(buf, i.Hash...)

// Encode Time
timeBytes := make([]byte, 8)
binary.LittleEndian.PutUint64(timeBytes, uint64(i.Time.Unix()))
buf = append(buf, timeBytes...)

// Encode AppHash
if len(i.Hash) != hashSize {
return nil, errors.New("invalid hash size")
}
buf = append(buf, i.AppHash...)

// Encode ChainID
chainIDLen := len(i.ChainID)
buf = append(buf, byte(chainIDLen))
buf = append(buf, []byte(i.ChainID)...)

return buf, nil
}

// FromBytes decodes the byte slice into an Info struct using little-endian encoding
func (i *Info) FromBytes(bytes []byte) error {
// Decode Height
i.Height = int64(binary.LittleEndian.Uint64(bytes[:8]))
bytes = bytes[8:]

// Decode Hash
i.Hash = make([]byte, hashSize)
copy(i.Hash, bytes[:hashSize])
bytes = bytes[hashSize:]

// Decode Time
unixTime := int64(binary.LittleEndian.Uint64(bytes[:8]))
i.Time = time.Unix(unixTime, 0)
bytes = bytes[8:]

// Decode AppHash
i.AppHash = make([]byte, len(bytes))
copy(i.AppHash, bytes)
bytes = bytes[hashSize:]

fmt.Println(len(bytes))
// Decode ChainID
chainIDLen := int(bytes[0])
bytes = bytes[1:]
if len(bytes) < chainIDLen {
return errors.New("invalid byte slice length")
}
i.ChainID = string(bytes[:chainIDLen])

return nil
}
60 changes: 60 additions & 0 deletions core/header/service_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package header

import (
"crypto/sha256"
"testing"
"time"

"github.com/stretchr/testify/require"
)

func TestInfo_Bytes(t *testing.T) {
sum := sha256.Sum256([]byte("test-chain"))
info := Info{
Height: 12345,
Hash: sum[:],
Time: time.Date(2024, time.January, 1, 0, 0, 0, 0, time.UTC),
AppHash: sum[:],
ChainID: "test-chain",
}

expectedBytes := []byte{
0x39, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Height (little-endian)
0x26, 0xb0, 0xb8, 0x3e, 0x72, 0x81, 0xbe, 0x3b, 0x11, 0x76, 0x58, 0xb6, 0xf2, 0x63, 0x6d, 0x3, 0x68, 0xca, 0xd3, 0xd7, 0x4f, 0x22, 0x24, 0x34, 0x28, 0xf5, 0x40, 0x1a, 0x4b, 0x70, 0x89, 0x7e, // Hash
0x80, 0x0, 0x92, 0x65, 0x0, 0x0, 0x0, 0x0, // Time (little-endian)
0x26, 0xb0, 0xb8, 0x3e, 0x72, 0x81, 0xbe, 0x3b, 0x11, 0x76, 0x58, 0xb6, 0xf2, 0x63, 0x6d, 0x3, 0x68, 0xca, 0xd3, 0xd7, 0x4f, 0x22, 0x24, 0x34, 0x28, 0xf5, 0x40, 0x1a, 0x4b, 0x70, 0x89, 0x7e, // Apphash
0x0A, // ChainID length
0x74, 0x65, 0x73, 0x74, 0x2d, 0x63, 0x68, 0x61, 0x69, 0x6e, // ChainID
}

bytes, err := info.Bytes()
require.NoError(t, err)
require.Equal(t, expectedBytes, bytes)
}

func TestInfo_FromBytes(t *testing.T) {
info := Info{}

// Test case 1: Valid byte slice
bytes := []byte{
0x39, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Height (little-endian)
0x26, 0xb0, 0xb8, 0x3e, 0x72, 0x81, 0xbe, 0x3b, 0x11, 0x76, 0x58, 0xb6, 0xf2, 0x63, 0x6d, 0x3, 0x68, 0xca, 0xd3, 0xd7, 0x4f, 0x22, 0x24, 0x34, 0x28, 0xf5, 0x40, 0x1a, 0x4b, 0x70, 0x89, 0x7e, // Hash
0x80, 0x0, 0x92, 0x65, 0x0, 0x0, 0x0, 0x0, // Time (little-endian)
0x26, 0xb0, 0xb8, 0x3e, 0x72, 0x81, 0xbe, 0x3b, 0x11, 0x76, 0x58, 0xb6, 0xf2, 0x63, 0x6d, 0x3, 0x68, 0xca, 0xd3, 0xd7, 0x4f, 0x22, 0x24, 0x34, 0x28, 0xf5, 0x40, 0x1a, 0x4b, 0x70, 0x89, 0x7e, // Apphash
0x0A, // ChainID length
0x74, 0x65, 0x73, 0x74, 0x2d, 0x63, 0x68, 0x61, 0x69, 0x6e, // ChainID
}

err := info.FromBytes(bytes)
require.NoError(t, err)
require.Equal(t, int64(12345), info.Height)
require.Equal(t, []byte{0x26, 0xb0, 0xb8, 0x3e, 0x72, 0x81, 0xbe, 0x3b, 0x11, 0x76, 0x58, 0xb6, 0xf2, 0x63, 0x6d, 0x3, 0x68, 0xca, 0xd3, 0xd7, 0x4f, 0x22, 0x24, 0x34, 0x28, 0xf5, 0x40, 0x1a, 0x4b, 0x70, 0x89, 0x7e}, info.Hash)
require.Equal(t, time.Unix(9, 0), info.Time)
require.Equal(t, []byte{0x26, 0xb0, 0xb8, 0x3e, 0x72, 0x81, 0xbe, 0x3b, 0x11, 0x76, 0x58, 0xb6, 0xf2, 0x63, 0x6d, 0x3, 0x68, 0xca, 0xd3, 0xd7, 0x4f, 0x22, 0x24, 0x34, 0x28, 0xf5, 0x40, 0x1a, 0x4b, 0x70, 0x89, 0x7e}, info.AppHash)
require.Equal(t, "test-chain", info.ChainID)

// Test case 2: Invalid byte slice length
err = info.FromBytes([]byte{})
require.Error(t, err)
require.Equal(t, "invalid byte slice length", err.Error())
}
6 changes: 3 additions & 3 deletions core/transaction/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ type Tx interface {
// Hash returns the unique identifier for the Tx.
Hash() [32]byte // TODO evaluate if 32 bytes is the right size & benchmark overhead of hashing instead of using identifier
// GetMessages returns the list of state transitions of the Tx.
GetMessages() []Type
GetMessages() ([]Type, error)
// GetSenders returns the tx state transition sender.
GetSenders() []Identity // TODO reduce this to a single identity if accepted
GetSenders() ([]Identity, error) // TODO reduce this to a single identity if accepted
// GetGasLimit returns the gas limit of the tx. Must return math.MaxUint64 for infinite gas
// txs.
GetGasLimit() uint64
GetGasLimit() (uint64, error)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

Codebase Verification

Several files in the codebase still use the old function signature for GetGasLimit without handling the new error return. These files need to be updated to align with the new function signature and error handling mechanism.

  • x/tx/signing/textual/internal/textualpb/textual.pulsar.go
  • types/tx/tx.pb.go
  • api/cosmos/tx/v1beta1/tx.pulsar.go
Analysis chain

Ensure all calls to GetGasLimit handle the new error return.

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify all function calls to `GetGasLimit` handle the new error return.

# Test: Search for the function usage. Expect: Only occurrences of the new signature.
rg --type go $'GetGasLimit'

Length of output: 629

// Bytes returns the encoded version of this tx. Note: this is ideally cached
// from the first instance of the decoding of the tx.
Bytes() []byte
Expand Down
1 change: 1 addition & 0 deletions go.work.example
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use (
./orm
./simapp
./tests
./server/v2/stf
./store
./store/v2
./tools/cosmovisor
Expand Down
14 changes: 10 additions & 4 deletions runtime/gas.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,15 @@ func (gm SDKGasMeter) Limit() storetypes.Gas {
}

func (gm SDKGasMeter) ConsumeGas(amount storetypes.Gas, descriptor string) {
gm.gm.Consume(amount, descriptor)
if err := gm.gm.Consume(amount, descriptor); err != nil {
panic(err)
}
}

func (gm SDKGasMeter) RefundGas(amount storetypes.Gas, descriptor string) {
gm.gm.Refund(amount, descriptor)
if err := gm.gm.Refund(amount, descriptor); err != nil {
panic(err)
}
}

func (gm SDKGasMeter) IsPastLimit() bool {
Expand All @@ -83,12 +87,14 @@ type CoreGasmeter struct {
gm storetypes.GasMeter
}

func (cgm CoreGasmeter) Consume(amount gas.Gas, descriptor string) {
func (cgm CoreGasmeter) Consume(amount gas.Gas, descriptor string) error {
cgm.gm.ConsumeGas(amount, descriptor)
return nil
}

func (cgm CoreGasmeter) Refund(amount gas.Gas, descriptor string) {
func (cgm CoreGasmeter) Refund(amount gas.Gas, descriptor string) error {
cgm.gm.RefundGas(amount, descriptor)
return nil
}

func (cgm CoreGasmeter) Remaining() gas.Gas {
Expand Down
Loading
Loading