diff --git a/consensus/state.go b/consensus/state.go index 0d82f2ab..2ed7197d 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -626,31 +626,7 @@ func (ms *MidState) fileContractElement(ts V1TransactionSupplement, id types.Fil if i, ok := ms.created[types.Hash256(id)]; ok { return ms.fces[i], true } - return ts.fileContractElement(id) -} - -func (ms *MidState) mustSiacoinElement(ts V1TransactionSupplement, id types.SiacoinOutputID) types.SiacoinElement { - sce, ok := ms.siacoinElement(ts, id) - if !ok { - panic("missing SiacoinElement") - } - return sce -} - -func (ms *MidState) mustSiafundElement(ts V1TransactionSupplement, id types.SiafundOutputID) types.SiafundElement { - sfe, ok := ms.siafundElement(ts, id) - if !ok { - panic("missing SiafundElement") - } - return sfe -} - -func (ms *MidState) mustFileContractElement(ts V1TransactionSupplement, id types.FileContractID) types.FileContractElement { - fce, ok := ms.fileContractElement(ts, id) - if !ok { - panic("missing FileContractElement") - } - return fce + return ts.revision(id) } func (ms *MidState) spent(id types.Hash256) (types.TransactionID, bool) { @@ -684,6 +660,25 @@ func NewMidState(s State) *MidState { } } +// A V1StorageProofSupplement pairs a file contract with the block ID used to +// derive its storage proof leaf index. +type V1StorageProofSupplement struct { + FileContract types.FileContractElement + WindowID types.BlockID +} + +// EncodeTo implements types.EncoderTo. +func (sps V1StorageProofSupplement) EncodeTo(e *types.Encoder) { + sps.FileContract.EncodeTo(e) + sps.WindowID.EncodeTo(e) +} + +// DecodeFrom implements types.DecoderFrom. +func (sps *V1StorageProofSupplement) DecodeFrom(d *types.Decoder) { + sps.FileContract.DecodeFrom(d) + sps.WindowID.DecodeFrom(d) +} + // A V1TransactionSupplement contains elements that are associated with a v1 // transaction, but not included in the transaction. For example, v1 // transactions reference the ID of each SiacoinOutput they spend, but do not @@ -695,8 +690,7 @@ type V1TransactionSupplement struct { SiacoinInputs []types.SiacoinElement SiafundInputs []types.SiafundElement RevisedFileContracts []types.FileContractElement - ValidFileContracts []types.FileContractElement - StorageProofBlockIDs []types.BlockID // must match ValidFileContracts + StorageProofs []V1StorageProofSupplement } // EncodeTo implements types.EncoderTo. @@ -704,7 +698,7 @@ func (ts V1TransactionSupplement) EncodeTo(e *types.Encoder) { types.EncodeSlice(e, ts.SiacoinInputs) types.EncodeSlice(e, ts.SiafundInputs) types.EncodeSlice(e, ts.RevisedFileContracts) - types.EncodeSlice(e, ts.ValidFileContracts) + types.EncodeSlice(e, ts.StorageProofs) } // DecodeFrom implements types.DecoderFrom. @@ -712,7 +706,7 @@ func (ts *V1TransactionSupplement) DecodeFrom(d *types.Decoder) { types.DecodeSlice(d, &ts.SiacoinInputs) types.DecodeSlice(d, &ts.SiafundInputs) types.DecodeSlice(d, &ts.RevisedFileContracts) - types.DecodeSlice(d, &ts.ValidFileContracts) + types.DecodeSlice(d, &ts.StorageProofs) } func (ts V1TransactionSupplement) siacoinElement(id types.SiacoinOutputID) (sce types.SiacoinElement, ok bool) { @@ -733,27 +727,22 @@ func (ts V1TransactionSupplement) siafundElement(id types.SiafundOutputID) (sfe return } -func (ts V1TransactionSupplement) fileContractElement(id types.FileContractID) (fce types.FileContractElement, ok bool) { +func (ts V1TransactionSupplement) revision(id types.FileContractID) (fce types.FileContractElement, ok bool) { for _, fce := range ts.RevisedFileContracts { if types.FileContractID(fce.ID) == id { return fce, true } } - for _, fce := range ts.ValidFileContracts { - if types.FileContractID(fce.ID) == id { - return fce, true - } - } return } -func (ts V1TransactionSupplement) storageProofWindowID(id types.FileContractID) types.BlockID { - for i, fce := range ts.ValidFileContracts { - if types.FileContractID(fce.ID) == id { - return ts.StorageProofBlockIDs[i] +func (ts V1TransactionSupplement) storageProof(id types.FileContractID) (sps V1StorageProofSupplement, ok bool) { + for _, sps := range ts.StorageProofs { + if types.FileContractID(sps.FileContract.ID) == id { + return sps, true } } - panic("missing contract for storage proof window ID") // developer error + return } // A V1BlockSupplement contains elements that are associated with a v1 block, diff --git a/consensus/update.go b/consensus/update.go index a9729ed8..77761ee7 100644 --- a/consensus/update.go +++ b/consensus/update.go @@ -455,13 +455,20 @@ func (ms *MidState) addAttestationElement(ae types.AttestationElement) { func (ms *MidState) ApplyTransaction(txn types.Transaction, ts V1TransactionSupplement) { txid := txn.ID() for _, sci := range txn.SiacoinInputs { - ms.spendSiacoinElement(ms.mustSiacoinElement(ts, sci.ParentID), txid) + sce, ok := ms.siacoinElement(ts, sci.ParentID) + if !ok { + panic("missing SiacoinElement") + } + ms.spendSiacoinElement(sce, txid) } for i, sco := range txn.SiacoinOutputs { ms.addSiacoinElement(txn.SiacoinOutputID(i), sco) } for _, sfi := range txn.SiafundInputs { - sfe := ms.mustSiafundElement(ts, sfi.ParentID) + sfe, ok := ms.siafundElement(ts, sfi.ParentID) + if !ok { + panic("missing SiafundElement") + } claimPortion := ms.siafundPool.Sub(sfe.ClaimStart).Div64(ms.base.SiafundCount()).Mul64(sfe.SiafundOutput.Value) ms.spendSiafundElement(sfe, txid) ms.addImmatureSiacoinElement(sfi.ParentID.ClaimOutputID(), types.SiacoinOutput{Value: claimPortion, Address: sfi.ClaimAddress}) @@ -473,12 +480,19 @@ func (ms *MidState) ApplyTransaction(txn types.Transaction, ts V1TransactionSupp ms.addFileContractElement(txn.FileContractID(i), fc) } for _, fcr := range txn.FileContractRevisions { - ms.reviseFileContractElement(ms.mustFileContractElement(ts, fcr.ParentID), fcr.FileContract) + fce, ok := ms.fileContractElement(ts, fcr.ParentID) + if !ok { + panic("missing FileContractElement") + } + ms.reviseFileContractElement(fce, fcr.FileContract) } for _, sp := range txn.StorageProofs { - fce := ms.mustFileContractElement(ts, sp.ParentID) - ms.resolveFileContractElement(fce, true, txid) - for i, sco := range fce.FileContract.ValidProofOutputs { + sps, ok := ts.storageProof(sp.ParentID) + if !ok { + panic("missing V1StorageProofSupplement") + } + ms.resolveFileContractElement(sps.FileContract, true, txid) + for i, sco := range sps.FileContract.FileContract.ValidProofOutputs { ms.addImmatureSiacoinElement(sp.ParentID.ValidOutputID(i), sco) } } diff --git a/consensus/update_test.go b/consensus/update_test.go index cbe8dab7..f420e8a2 100644 --- a/consensus/update_test.go +++ b/consensus/update_test.go @@ -828,8 +828,10 @@ func TestApplyRevertBlockV1(t *testing.T) { // add block with storage proof bs = db.supplementTipBlock(b5) - bs.Transactions[0].ValidFileContracts = append(bs.Transactions[0].ValidFileContracts, db.fces[txnB5.StorageProofs[0].ParentID]) - bs.Transactions[0].StorageProofBlockIDs = append(bs.Transactions[0].StorageProofBlockIDs, b3.ID()) + bs.Transactions[0].StorageProofs = append(bs.Transactions[0].StorageProofs, V1StorageProofSupplement{ + FileContract: db.fces[txnB5.StorageProofs[0].ParentID], + WindowID: b3.ID(), + }) prev = cs if au, err := addBlock(&b5, bs); err != nil { t.Fatal(err) diff --git a/consensus/validation.go b/consensus/validation.go index 8519e963..0377610c 100644 --- a/consensus/validation.go +++ b/consensus/validation.go @@ -354,13 +354,12 @@ func validateFileContracts(ms *MidState, txn types.Transaction, ts V1Transaction if txid, ok := ms.spent(types.Hash256(sp.ParentID)); ok { return fmt.Errorf("storage proof %v conflicts with previous proof (in %v)", i, txid) } - fce, ok := ms.fileContractElement(ts, sp.ParentID) + sps, ok := ts.storageProof(sp.ParentID) if !ok { return fmt.Errorf("storage proof %v references nonexistent file contract", i) } - fc := fce.FileContract - windowID := ts.storageProofWindowID(sp.ParentID) - leafIndex := ms.base.StorageProofLeafIndex(fc.Filesize, windowID, sp.ParentID) + fc := sps.FileContract.FileContract + leafIndex := ms.base.StorageProofLeafIndex(fc.Filesize, sps.WindowID, sp.ParentID) leaf := storageProofLeaf(leafIndex, fc.Filesize, sp.Leaf) if leaf == nil { continue @@ -923,14 +922,11 @@ func validateSupplement(s State, b types.Block, bs V1BlockSupplement) error { return fmt.Errorf("revised file contract %v is not present in the accumulator", fce.ID) } } - for _, fce := range txn.ValidFileContracts { - if !s.Elements.containsUnresolvedFileContractElement(fce) { - return fmt.Errorf("valid file contract %v is not present in the accumulator", fce.ID) + for _, sps := range txn.StorageProofs { + if !s.Elements.containsUnresolvedFileContractElement(sps.FileContract) { + return fmt.Errorf("valid file contract %v is not present in the accumulator", sps.FileContract.ID) } } - if len(txn.StorageProofBlockIDs) != len(txn.ValidFileContracts) { - return errors.New("incorrect number of storage proof block IDs") - } } for _, fce := range bs.ExpiringFileContracts { if !s.Elements.containsUnresolvedFileContractElement(fce) {