Skip to content

Commit

Permalink
rhp4,chain: simplify renew, move proof updates to chain manager
Browse files Browse the repository at this point in the history
  • Loading branch information
n8maninger committed Oct 3, 2024
1 parent 1406d3d commit 6e43a93
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 257 deletions.
79 changes: 59 additions & 20 deletions chain/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -949,7 +949,7 @@ func (m *Manager) V2TransactionSet(basis types.ChainIndex, txn types.V2Transacti
m.revalidatePool()

// update the transaction's basis to match tip
_, txns, err := m.updateV2TransactionSet(basis, []types.V2Transaction{txn})
txns, err := m.UpdateV2TransactionSet([]types.V2Transaction{txn}, basis, m.tipState.Index)
if err != nil {
return types.ChainIndex{}, nil, fmt.Errorf("failed to update transaction set basis: %w", err)
} else if len(txns) == 0 {
Expand Down Expand Up @@ -1086,47 +1086,86 @@ func (m *Manager) AddPoolTransactions(txns []types.Transaction) (known bool, err
return
}

// updateV2TransactionSet updates the basis of a transaction set to the current
// tip. If the basis is already the tip, the transaction set is returned as-is.
// Any transactions that were confirmed are removed from the set. Any ephemeral
// state elements that were created by an update are updated.
// UpdateStateElement updates the basis of a state element from "from" to "to".
// If from and to are equal, the state element is not modified.
func (m *Manager) UpdateStateElement(se *types.StateElement, from, to types.ChainIndex) error {
if from == to {
return nil
}

revert, apply, err := m.reorgPath(from, to)
if err != nil {
return fmt.Errorf("couldn't determine reorg path from %v to %v: %w", from, to, err)
} else if len(revert)+len(apply) > 144 {
return fmt.Errorf("reorg path from %v to %v is too long (-%v +%v)", from, to, len(revert), len(apply))
}
for _, index := range revert {
b, _, cs, ok := blockAndParent(m.store, index.ID)
if !ok {
return fmt.Errorf("missing reverted block at index %v", index)
} else if b.V2 == nil {
return fmt.Errorf("reorg path from %v to %v contains a non-v2 block (%v)", from, to, index)
}
// NOTE: since we are post-hardfork, we don't need a v1 supplement
cru := consensus.RevertBlock(cs, b, consensus.V1BlockSupplement{})
cru.UpdateElementProof(se)
}

for _, index := range apply {
b, _, cs, ok := blockAndParent(m.store, index.ID)
if !ok {
return fmt.Errorf("missing applied block at index %v", index)
} else if b.V2 == nil {
return fmt.Errorf("reorg path from %v to %v contains a non-v2 block (%v)", from, to, index)
}
// NOTE: since we are post-hardfork, we don't need a v1 supplement or ancestorTimestamp
_, cau := consensus.ApplyBlock(cs, b, consensus.V1BlockSupplement{}, time.Time{})
cau.UpdateElementProof(se)
}
return nil
}

// UpdateV2TransactionSet updates the basis of a transaction set from "from" to "to".
// If from and to are equal, the transaction set is returned as-is.
// Any transactions that were confirmed are removed from the set.
// Any ephemeral state elements that were created by an update are updated.
//
// If it is undesirable to modify the transaction set, deep-copy it
// before calling this method.
func (m *Manager) updateV2TransactionSet(basis types.ChainIndex, txns []types.V2Transaction) (types.ChainIndex, []types.V2Transaction, error) {
if basis == m.tipState.Index {
return basis, txns, nil
func (m *Manager) UpdateV2TransactionSet(txns []types.V2Transaction, from, to types.ChainIndex) ([]types.V2Transaction, error) {
if from == to {
return txns, nil
}

// bring txns up-to-date
revert, apply, err := m.reorgPath(basis, m.tipState.Index)
revert, apply, err := m.reorgPath(from, to)
if err != nil {
return types.ChainIndex{}, nil, fmt.Errorf("couldn't determine reorg path from %v to %v: %w", basis, m.tipState.Index, err)
return nil, fmt.Errorf("couldn't determine reorg path from %v to %v: %w", from, to, err)
} else if len(revert)+len(apply) > 144 {
return types.ChainIndex{}, nil, fmt.Errorf("reorg path from %v to %v is too long (-%v +%v)", basis, m.tipState.Index, len(revert), len(apply))
return nil, fmt.Errorf("reorg path from %v to %v is too long (-%v +%v)", from, to, len(revert), len(apply))
}
for _, index := range revert {
b, _, cs, ok := blockAndParent(m.store, index.ID)
if !ok {
return types.ChainIndex{}, nil, fmt.Errorf("missing reverted block at index %v", index)
return nil, fmt.Errorf("missing reverted block at index %v", index)
} else if b.V2 == nil {
return types.ChainIndex{}, nil, fmt.Errorf("reorg path from %v to %v contains a non-v2 block (%v)", basis, m.tipState.Index, index)
return nil, fmt.Errorf("reorg path from %v to %v contains a non-v2 block (%v)", from, to, index)
}
// NOTE: since we are post-hardfork, we don't need a v1 supplement
cru := consensus.RevertBlock(cs, b, consensus.V1BlockSupplement{})
for i := range txns {
if !updateTxnProofs(&txns[i], cru.UpdateElementProof, cs.Elements.NumLeaves) {
return types.ChainIndex{}, nil, fmt.Errorf("transaction %v references element that does not exist in our chain", txns[i].ID())
return nil, fmt.Errorf("transaction %v references element that does not exist in our chain", txns[i].ID())
}
}
}

for _, index := range apply {
b, _, cs, ok := blockAndParent(m.store, index.ID)
if !ok {
return types.ChainIndex{}, nil, fmt.Errorf("missing applied block at index %v", index)
return nil, fmt.Errorf("missing applied block at index %v", index)
} else if b.V2 == nil {
return types.ChainIndex{}, nil, fmt.Errorf("reorg path from %v to %v contains a non-v2 block (%v)", basis, m.tipState.Index, index)
return nil, fmt.Errorf("reorg path from %v to %v contains a non-v2 block (%v)", from, to, index)
}
// NOTE: since we are post-hardfork, we don't need a v1 supplement or ancestorTimestamp
cs, cau := consensus.ApplyBlock(cs, b, consensus.V1BlockSupplement{}, time.Time{})
Expand Down Expand Up @@ -1154,7 +1193,6 @@ func (m *Manager) updateV2TransactionSet(basis types.ChainIndex, txns []types.V2
// remove any transactions that were confirmed in this block
continue
}
rem = append(rem, txns[i])

// update the state elements for any confirmed ephemeral elements
for j := range txns[i].SiacoinInputs {
Expand Down Expand Up @@ -1182,11 +1220,12 @@ func (m *Manager) updateV2TransactionSet(basis types.ChainIndex, txns []types.V2

// NOTE: all elements guaranteed to exist from here on, so no
// need to check this return value
updateTxnProofs(&rem[len(rem)-1], cau.UpdateElementProof, cs.Elements.NumLeaves)
updateTxnProofs(&txns[i], cau.UpdateElementProof, cs.Elements.NumLeaves)
rem = append(rem, txns[i])
}
txns = rem
}
return m.tipState.Index, txns, nil
return txns, nil
}

// AddV2PoolTransactions validates a transaction set and adds it to the txpool.
Expand Down Expand Up @@ -1220,7 +1259,7 @@ func (m *Manager) AddV2PoolTransactions(basis types.ChainIndex, txns []types.V2T
}

// update the transaction set to the current tip
_, txns, err := m.updateV2TransactionSet(basis, txns)
txns, err := m.UpdateV2TransactionSet(txns, basis, m.tipState.Index)
if err != nil {
return false, m.markBadTxnSet(setID, fmt.Errorf("failed to update set basis: %w", err))
} else if len(txns) == 0 {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.23.0

require (
go.etcd.io/bbolt v1.3.11
go.sia.tech/core v0.4.8-0.20241002233523-418236837b5a
go.sia.tech/core v0.4.8-0.20241003192046-425f95763c90
go.sia.tech/mux v1.3.0
go.uber.org/zap v1.27.0
golang.org/x/crypto v0.27.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
go.sia.tech/core v0.4.8-0.20241002233523-418236837b5a h1:Lz7h42eZCk8iI4/agdWNwlVneqaybxkV1lor+Eavzso=
go.sia.tech/core v0.4.8-0.20241002233523-418236837b5a/go.mod h1:j2Ke8ihV8or7d2VDrFZWcCkwSVHO0DNMQJAGs9Qop2M=
go.sia.tech/core v0.4.8-0.20241003192046-425f95763c90 h1:R/G7XXyzLKelfGBGT6XQpih379v5jJx6T4AsjLwyjJc=
go.sia.tech/core v0.4.8-0.20241003192046-425f95763c90/go.mod h1:j2Ke8ihV8or7d2VDrFZWcCkwSVHO0DNMQJAGs9Qop2M=
go.sia.tech/mux v1.3.0 h1:hgR34IEkqvfBKUJkAzGi31OADeW2y7D6Bmy/Jcbop9c=
go.sia.tech/mux v1.3.0/go.mod h1:I46++RD4beqA3cW9Xm9SwXbezwPqLvHhVs9HLpDtt58=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
Expand Down
64 changes: 25 additions & 39 deletions rhp/v4/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -649,48 +649,28 @@ func RPCRenewContract(ctx context.Context, t TransportClient, tp TxPool, signer
}

renterCost, hostCost := rhp4.RenewalCost(cs, p, renewal, renewalTxn.MinerFee)

basis := cs.Index // start with a decent basis and overwrite it if a setup transaction is needed
var renewalParents []types.V2Transaction
if !renterCost.IsZero() {
setupTxn := types.V2Transaction{
SiacoinOutputs: []types.SiacoinOutput{
{Address: renewal.NewContract.RenterOutput.Address, Value: renterCost},
},
}
var err error
var toSign []int
basis, toSign, err = signer.FundV2Transaction(&setupTxn, renterCost)
if err != nil {
return RPCRenewContractResult{}, fmt.Errorf("failed to fund transaction: %w", err)
}
signer.SignV2Inputs(&setupTxn, toSign)

basis, renewalParents, err = tp.V2TransactionSet(basis, setupTxn)
if err != nil {
return RPCRenewContractResult{}, fmt.Errorf("failed to get transaction set: %w", err)
}
setupTxn = renewalParents[len(renewalParents)-1]

renewalTxn.SiacoinInputs = append(renewalTxn.SiacoinInputs, types.V2SiacoinInput{
Parent: setupTxn.EphemeralSiacoinOutput(0),
})
signer.SignV2Inputs(&renewalTxn, []int{0})
req := rhp4.RPCRenewContractRequest{
Prices: p,
Renewal: params,
MinerFee: renewalTxn.MinerFee,
Basis: cs.Index,
}

renterSiacoinElements := make([]types.SiacoinElement, 0, len(renewalTxn.SiacoinInputs))
for _, i := range renewalTxn.SiacoinInputs {
renterSiacoinElements = append(renterSiacoinElements, i.Parent)
basis, toSign, err := signer.FundV2Transaction(&renewalTxn, renterCost)
if err != nil {
return RPCRenewContractResult{}, fmt.Errorf("failed to fund transaction: %w", err)
}
signer.SignV2Inputs(&renewalTxn, toSign)

req := rhp4.RPCRenewContractRequest{
Prices: p,
Renewal: params,
MinerFee: renewalTxn.MinerFee,
Basis: basis,
RenterInputs: renterSiacoinElements,
RenterParents: renewalParents,
req.Basis, req.RenterParents, err = tp.V2TransactionSet(basis, renewalTxn)
if err != nil {
return RPCRenewContractResult{}, fmt.Errorf("failed to get transaction set: %w", err)
}
for _, si := range renewalTxn.SiacoinInputs {
req.RenterInputs = append(req.RenterInputs, si.Parent)
}
req.RenterParents = req.RenterParents[:len(req.RenterParents)-1] // last transaction is the renewal

sigHash := req.ChallengeSigHash(existing.RevisionNumber)
req.ChallengeSignature = signer.SignHash(sigHash)

Expand All @@ -714,8 +694,14 @@ func RPCRenewContract(ctx context.Context, t TransportClient, tp TxPool, signer
}

// verify the host added enough inputs
if !hostInputSum.Equals(hostCost) {
if n := hostInputSum.Cmp(hostCost); n < 0 {
return RPCRenewContractResult{}, fmt.Errorf("expected host to fund %v, got %v", hostCost, hostInputSum)
} else if n > 0 {
// add change output
renewalTxn.SiacoinOutputs = append(renewalTxn.SiacoinOutputs, types.SiacoinOutput{
Address: existing.HostOutput.Address,
Value: hostInputSum.Sub(hostCost),
})
}

// sign the renter inputs
Expand All @@ -728,7 +714,7 @@ func RPCRenewContract(ctx context.Context, t TransportClient, tp TxPool, signer
renterPolicyResp := rhp4.RPCRenewContractSecondResponse{
RenterRenewalSignature: renewal.RenterSignature,
}
for _, si := range renewalTxn.SiacoinInputs[:len(renterSiacoinElements)] {
for _, si := range renewalTxn.SiacoinInputs[:len(req.RenterInputs)] {
renterPolicyResp.RenterSatisfiedPolicies = append(renterPolicyResp.RenterSatisfiedPolicies, si.SatisfiedPolicy)
}
if err := rhp4.WriteResponse(s, &renterPolicyResp); err != nil {
Expand Down
Loading

0 comments on commit 6e43a93

Please sign in to comment.