Skip to content

Commit

Permalink
Remove TODO and cleanup expiration code
Browse files Browse the repository at this point in the history
  • Loading branch information
2opremio committed Sep 15, 2023
1 parent febaa47 commit 9471897
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 87 deletions.
1 change: 0 additions & 1 deletion cmd/soroban-cli/src/commands/contract/bump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,6 @@ impl Cmd {
return Err(Error::LedgerEntryNotFound);
}

// TODO: double-check that this match is correct
match (&operations[0].changes[0], &operations[0].changes[1]) {
(
LedgerEntryChange::State(_),
Expand Down
67 changes: 13 additions & 54 deletions cmd/soroban-rpc/internal/test/cli_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package test

import (
"context"
"crypto/sha256"
"encoding/hex"
"fmt"
Expand All @@ -19,8 +18,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gotest.tools/v3/icmd"

"github.com/stellar/soroban-tools/cmd/soroban-rpc/internal/methods"
)

func TestCLIContractInstall(t *testing.T) {
Expand Down Expand Up @@ -79,7 +76,7 @@ func TestCLIRestorePreamble(t *testing.T) {
// This ensures that the CLI restores the entry (using the RestorePreamble in the simulateTransaction response)
ch := jhttp.NewChannel(test.sorobanRPCURL(), nil)
client := jrpc2.NewClient(ch, nil)
waitForLedgerEntryToExpire(t, client, expirationKey(t, counterLedgerKey(t, strkeyContractID)))
waitForLedgerEntryToExpire(t, client, getExpirationKeyForCounterLedgerEntry(t, strkeyContractID))

count = runSuccessfulCLICmd(t, fmt.Sprintf("contract invoke --id %s -- inc", strkeyContractID))
require.Equal(t, "3", count)
Expand All @@ -94,7 +91,8 @@ func TestCLIBump(t *testing.T) {
ch := jhttp.NewChannel(test.sorobanRPCURL(), nil)
client := jrpc2.NewClient(ch, nil)

initialExpirationSeq := getExpirationForLedgerEntry(t, client, expirationKey(t, counterLedgerKey(t, strkeyContractID)))
expirationKey := getExpirationKeyForCounterLedgerEntry(t, strkeyContractID)
initialExpirationSeq := getExpirationForLedgerEntry(t, client, expirationKey)

bumpOutput := runSuccessfulCLICmd(
t,
Expand All @@ -104,7 +102,7 @@ func TestCLIBump(t *testing.T) {
),
)

newExpirationSeq := getExpirationForLedgerEntry(t, client, expirationKey(t, counterLedgerKey(t, strkeyContractID)))
newExpirationSeq := getExpirationForLedgerEntry(t, client, expirationKey)
assert.Greater(t, newExpirationSeq, initialExpirationSeq)
assert.Equal(t, fmt.Sprintf("New expiration ledger: %d", newExpirationSeq), bumpOutput)
}
Expand All @@ -118,11 +116,11 @@ func TestCLIRestore(t *testing.T) {
ch := jhttp.NewChannel(test.sorobanRPCURL(), nil)
client := jrpc2.NewClient(ch, nil)

initialExpirationSeq := getExpirationForLedgerEntry(t, client, expirationKey(t, counterLedgerKey(t, strkeyContractID)))

expirationKey := getExpirationKeyForCounterLedgerEntry(t, strkeyContractID)
initialExpirationSeq := getExpirationForLedgerEntry(t, client, expirationKey)
// Wait for the counter ledger entry to expire and successfully invoke the `inc` contract function again
// This ensures that the CLI restores the entry (using the RestorePreamble in the simulateTransaction response)
waitForLedgerEntryToExpire(t, client, expirationKey(t, counterLedgerKey(t, strkeyContractID)))
waitForLedgerEntryToExpire(t, client, expirationKey)

restoreOutput := runSuccessfulCLICmd(
t,
Expand All @@ -132,60 +130,21 @@ func TestCLIRestore(t *testing.T) {
),
)

newExpirationSeq := getExpirationForLedgerEntry(t, client, expirationKey(t, counterLedgerKey(t, strkeyContractID)))
newExpirationSeq := getExpirationForLedgerEntry(t, client, getExpirationKey(t, getCounterLedgerKey(parseContractStrKey(t, strkeyContractID))))
assert.Greater(t, newExpirationSeq, initialExpirationSeq)
assert.Equal(t, fmt.Sprintf("New expiration ledger: %d", newExpirationSeq), restoreOutput)
}

func getExpirationForLedgerEntry(t *testing.T, client *jrpc2.Client, ledgerKey xdr.LedgerKey) xdr.Uint32 {
keyB64, err := xdr.MarshalBase64(ledgerKey)
require.NoError(t, err)
getLedgerEntryrequest := methods.GetLedgerEntryRequest{
Key: keyB64,
}
var getLedgerEntryResult methods.GetLedgerEntryResponse
err = client.CallResult(context.Background(), "getLedgerEntry", getLedgerEntryrequest, &getLedgerEntryResult)
assert.NoError(t, err)
var entry xdr.LedgerEntryData
assert.NoError(t, xdr.SafeUnmarshalBase64(getLedgerEntryResult.XDR, &entry))

assert.Equal(t, xdr.LedgerEntryTypeExpiration, entry.Type)
return entry.Expiration.ExpirationLedgerSeq
}

func expirationKey(t *testing.T, key xdr.LedgerKey) xdr.LedgerKey {
binKey, err := key.MarshalBinary()
assert.NoError(t, err)
return xdr.LedgerKey{
Type: xdr.LedgerEntryTypeExpiration,
Expiration: &xdr.LedgerKeyExpiration{
KeyHash: sha256.Sum256(binKey),
},
}
func getExpirationKeyForCounterLedgerEntry(t *testing.T, strkeyContractID string) xdr.LedgerKey {
return getExpirationKey(t, getCounterLedgerKey(parseContractStrKey(t, strkeyContractID)))
}

func counterLedgerKey(t *testing.T, strkeyContractID string) xdr.LedgerKey {
func parseContractStrKey(t *testing.T, strkeyContractID string) [32]byte {
contractIDBytes := strkey.MustDecode(strkey.VersionByteContract, strkeyContractID)
require.Len(t, contractIDBytes, 32)
var contractID [32]byte
require.Len(t, contractIDBytes, len(contractID))
copy(contractID[:], contractIDBytes)
contractIDHash := xdr.Hash(contractID)
counterSym := xdr.ScSymbol("COUNTER")
key := xdr.LedgerKey{
Type: xdr.LedgerEntryTypeContractData,
ContractData: &xdr.LedgerKeyContractData{
Contract: xdr.ScAddress{
Type: xdr.ScAddressTypeScAddressTypeContract,
ContractId: &contractIDHash,
},
Key: xdr.ScVal{
Type: xdr.ScValTypeScvSymbol,
Sym: &counterSym,
},
Durability: xdr.ContractDataDurabilityPersistent,
},
}
return key
return contractID
}

func runSuccessfulCLICmd(t *testing.T, cmd string) string {
Expand Down
88 changes: 56 additions & 32 deletions cmd/soroban-rpc/internal/test/simulate_transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func createInstallContractCodeOperation(sourceAccount string, contractCode []byt
}
}

func createCreateContractOperation(t *testing.T, sourceAccount string, contractCode []byte, networkPassphrase string) *txnbuild.InvokeHostFunction {
func createCreateContractOperation(sourceAccount string, contractCode []byte) *txnbuild.InvokeHostFunction {
saltParam := xdr.Uint256(testSalt)
contractHash := xdr.Hash(sha256.Sum256(contractCode))

Expand Down Expand Up @@ -271,7 +271,7 @@ func TestSimulateTransactionSucceeds(t *testing.T) {

resultForRequestWithoutOpSource := simulateTransactionFromTxParams(t, client, params)
// Let's not compare the latest ledger since it may change
resultForRequestWithoutOpSource.LatestLedger = resultForRequestWithoutOpSource.LatestLedger
result.LatestLedger = resultForRequestWithoutOpSource.LatestLedger
assert.Equal(t, result, resultForRequestWithoutOpSource)

// test that operation source account takes precedence over tx source account
Expand Down Expand Up @@ -326,7 +326,7 @@ func TestSimulateTransactionWithAuth(t *testing.T) {
assert.NoError(t, err)
sendSuccessfulTransaction(t, client, sourceAccount, tx)

deployContractOp := createCreateContractOperation(t, address, helloWorldContract, StandaloneNetworkPassphrase)
deployContractOp := createCreateContractOperation(address, helloWorldContract)
deployContractParams := txnbuild.TransactionParams{
SourceAccount: &account,
IncrementSequenceNum: true,
Expand Down Expand Up @@ -388,7 +388,7 @@ func TestSimulateInvokeContractTransactionSucceeds(t *testing.T) {
SourceAccount: &account,
IncrementSequenceNum: true,
Operations: []txnbuild.Operation{
createCreateContractOperation(t, address, helloWorldContract, StandaloneNetworkPassphrase),
createCreateContractOperation(address, helloWorldContract),
},
BaseFee: txnbuild.MinBaseFee,
Preconditions: txnbuild.Preconditions{
Expand Down Expand Up @@ -598,7 +598,7 @@ func TestSimulateTransactionMultipleOperations(t *testing.T) {
IncrementSequenceNum: false,
Operations: []txnbuild.Operation{
createInstallContractCodeOperation(sourceAccount, contractBinary),
createCreateContractOperation(t, sourceAccount, contractBinary, StandaloneNetworkPassphrase),
createCreateContractOperation(sourceAccount, contractBinary),
},
BaseFee: txnbuild.MinBaseFee,
Memo: nil,
Expand Down Expand Up @@ -696,7 +696,7 @@ func TestSimulateTransactionBumpAndRestoreFootprint(t *testing.T) {
SourceAccount: &account,
IncrementSequenceNum: true,
Operations: []txnbuild.Operation{
createCreateContractOperation(t, address, helloWorldContract, StandaloneNetworkPassphrase),
createCreateContractOperation(address, helloWorldContract),
},
BaseFee: txnbuild.MinBaseFee,
Preconditions: txnbuild.Preconditions{
Expand Down Expand Up @@ -729,32 +729,8 @@ func TestSimulateTransactionBumpAndRestoreFootprint(t *testing.T) {
sendSuccessfulTransaction(t, client, sourceAccount, tx)

// get the counter ledger entry expiration
contractIDHash := xdr.Hash(contractID)
counterSym := xdr.ScSymbol("COUNTER")
key := xdr.LedgerKey{
Type: xdr.LedgerEntryTypeContractData,
ContractData: &xdr.LedgerKeyContractData{
Contract: xdr.ScAddress{
Type: xdr.ScAddressTypeScAddressTypeContract,
ContractId: &contractIDHash,
},
Key: xdr.ScVal{
Type: xdr.ScValTypeScvSymbol,
Sym: &counterSym,
},
Durability: xdr.ContractDataDurabilityPersistent,
},
}

binKey, err := key.MarshalBinary()
assert.NoError(t, err)

expirationKey := xdr.LedgerKey{
Type: xdr.LedgerEntryTypeExpiration,
Expiration: &xdr.LedgerKeyExpiration{
KeyHash: sha256.Sum256(binKey),
},
}
key := getCounterLedgerKey(contractID)
expirationKey := getExpirationKey(t, key)

initialExpirationSeq := getExpirationForLedgerEntry(t, client, expirationKey)

Expand Down Expand Up @@ -854,6 +830,54 @@ func TestSimulateTransactionBumpAndRestoreFootprint(t *testing.T) {
sendSuccessfulTransaction(t, client, sourceAccount, tx)
}

func getExpirationKey(t *testing.T, key xdr.LedgerKey) xdr.LedgerKey {
assert.True(t, key.Type == xdr.LedgerEntryTypeContractCode || key.Type == xdr.LedgerEntryTypeContractData)
binKey, err := key.MarshalBinary()
assert.NoError(t, err)
return xdr.LedgerKey{
Type: xdr.LedgerEntryTypeExpiration,
Expiration: &xdr.LedgerKeyExpiration{
KeyHash: sha256.Sum256(binKey),
},
}
}

func getCounterLedgerKey(contractID [32]byte) xdr.LedgerKey {
contractIDHash := xdr.Hash(contractID)
counterSym := xdr.ScSymbol("COUNTER")
key := xdr.LedgerKey{
Type: xdr.LedgerEntryTypeContractData,
ContractData: &xdr.LedgerKeyContractData{
Contract: xdr.ScAddress{
Type: xdr.ScAddressTypeScAddressTypeContract,
ContractId: &contractIDHash,
},
Key: xdr.ScVal{
Type: xdr.ScValTypeScvSymbol,
Sym: &counterSym,
},
Durability: xdr.ContractDataDurabilityPersistent,
},
}
return key
}

func getExpirationForLedgerEntry(t *testing.T, client *jrpc2.Client, expirationLedgerKey xdr.LedgerKey) xdr.Uint32 {
keyB64, err := xdr.MarshalBase64(expirationLedgerKey)
require.NoError(t, err)
getLedgerEntryrequest := methods.GetLedgerEntryRequest{
Key: keyB64,
}
var getLedgerEntryResult methods.GetLedgerEntryResponse
err = client.CallResult(context.Background(), "getLedgerEntry", getLedgerEntryrequest, &getLedgerEntryResult)
assert.NoError(t, err)
var entry xdr.LedgerEntryData
assert.NoError(t, xdr.SafeUnmarshalBase64(getLedgerEntryResult.XDR, &entry))

assert.Equal(t, xdr.LedgerEntryTypeExpiration, entry.Type)
return entry.Expiration.ExpirationLedgerSeq
}

func waitForLedgerEntryToExpire(t *testing.T, client *jrpc2.Client, expirationKey xdr.LedgerKey) {
keyB64, err := xdr.MarshalBase64(expirationKey)
require.NoError(t, err)
Expand Down

0 comments on commit 9471897

Please sign in to comment.