diff --git a/chain/chain_test.go b/chain/chain_test.go index 8f2ac16..d4611ce 100644 --- a/chain/chain_test.go +++ b/chain/chain_test.go @@ -13,7 +13,7 @@ import ( type memState struct { index types.ChainIndex - utxos map[types.Hash256]types.SiacoinElement + utxos map[types.SiacoinOutputID]types.SiacoinElement chainIndexElements []types.ChainIndexElement } @@ -109,7 +109,7 @@ func (ms *memState) SpendableElement(t *testing.T) (se types.SiacoinElement) { func newMemState() *memState { return &memState{ - utxos: make(map[types.Hash256]types.SiacoinElement), + utxos: make(map[types.SiacoinOutputID]types.SiacoinElement), } } diff --git a/chain/db.go b/chain/db.go index bffec8f..9f1eda0 100644 --- a/chain/db.go +++ b/chain/db.go @@ -352,13 +352,13 @@ func (db *DBStore) getElementProof(leafIndex, numLeaves uint64) (proof []types.H func (db *DBStore) getSiacoinElement(id types.SiacoinOutputID, numLeaves uint64) (sce types.SiacoinElement, ok bool) { ok = db.bucket(bSiacoinElements).get(id[:], &sce) if ok { - sce.MerkleProof = db.getElementProof(sce.LeafIndex, numLeaves) + sce.StateElement.MerkleProof = db.getElementProof(sce.StateElement.LeafIndex, numLeaves) } return } func (db *DBStore) putSiacoinElement(sce types.SiacoinElement) { - sce.MerkleProof = nil + sce.StateElement.MerkleProof = nil db.bucket(bSiacoinElements).put(sce.ID[:], sce) } @@ -369,13 +369,13 @@ func (db *DBStore) deleteSiacoinElement(id types.SiacoinOutputID) { func (db *DBStore) getSiafundElement(id types.SiafundOutputID, numLeaves uint64) (sfe types.SiafundElement, ok bool) { ok = db.bucket(bSiafundElements).get(id[:], &sfe) if ok { - sfe.MerkleProof = db.getElementProof(sfe.LeafIndex, numLeaves) + sfe.StateElement.MerkleProof = db.getElementProof(sfe.StateElement.LeafIndex, numLeaves) } return } func (db *DBStore) putSiafundElement(sfe types.SiafundElement) { - sfe.MerkleProof = nil + sfe.StateElement.MerkleProof = nil db.bucket(bSiafundElements).put(sfe.ID[:], sfe) } @@ -386,13 +386,13 @@ func (db *DBStore) deleteSiafundElement(id types.SiafundOutputID) { func (db *DBStore) getFileContractElement(id types.FileContractID, numLeaves uint64) (fce types.FileContractElement, ok bool) { ok = db.bucket(bFileContractElements).get(id[:], &fce) if ok { - fce.MerkleProof = db.getElementProof(fce.LeafIndex, numLeaves) + fce.StateElement.MerkleProof = db.getElementProof(fce.StateElement.LeafIndex, numLeaves) } return } func (db *DBStore) putFileContractElement(fce types.FileContractElement) { - fce.MerkleProof = nil + fce.StateElement.MerkleProof = nil db.bucket(bFileContractElements).put(fce.ID[:], fce) } diff --git a/chain/manager.go b/chain/manager.go index 22440f2..d1b6288 100644 --- a/chain/manager.go +++ b/chain/manager.go @@ -667,48 +667,48 @@ func (m *Manager) revertPoolUpdate(cru consensus.RevertUpdate, cs consensus.Stat // applying a block can make ephemeral elements in the txpool non-ephemeral; // here, we undo that var uncreated map[types.Hash256]bool - replaceEphemeral := func(e *types.StateElement) { + replaceEphemeral := func(id types.Hash256, e *types.StateElement) { if e.LeafIndex == types.UnassignedLeafIndex { return } else if uncreated == nil { uncreated = make(map[types.Hash256]bool) cru.ForEachSiacoinElement(func(sce types.SiacoinElement, created, spent bool) { if created { - uncreated[sce.ID] = true + uncreated[types.Hash256(sce.ID)] = true } }) cru.ForEachSiafundElement(func(sfe types.SiafundElement, created, spent bool) { if created { - uncreated[sfe.ID] = true + uncreated[types.Hash256(sfe.ID)] = true } }) cru.ForEachFileContractElement(func(fce types.FileContractElement, created bool, rev *types.FileContractElement, resolved, valid bool) { if created { - uncreated[fce.ID] = true + uncreated[types.Hash256(fce.ID)] = true } }) cru.ForEachV2FileContractElement(func(fce types.V2FileContractElement, created bool, rev *types.V2FileContractElement, res types.V2FileContractResolutionType) { if created { - uncreated[fce.ID] = true + uncreated[types.Hash256(fce.ID)] = true } }) } - if uncreated[e.ID] { - *e = types.StateElement{ID: e.ID, LeafIndex: types.UnassignedLeafIndex} + if uncreated[id] { + *e = types.StateElement{LeafIndex: types.UnassignedLeafIndex} } } for _, txn := range m.txpool.v2txns { - for i := range txn.SiacoinInputs { - replaceEphemeral(&txn.SiacoinInputs[i].Parent.StateElement) + for i, si := range txn.SiacoinInputs { + replaceEphemeral(types.Hash256(si.Parent.ID), &txn.SiacoinInputs[i].Parent.StateElement) } - for i := range txn.SiafundInputs { - replaceEphemeral(&txn.SiafundInputs[i].Parent.StateElement) + for i, si := range txn.SiafundInputs { + replaceEphemeral(types.Hash256(si.Parent.ID), &txn.SiafundInputs[i].Parent.StateElement) } - for i := range txn.FileContractRevisions { - replaceEphemeral(&txn.FileContractRevisions[i].Parent.StateElement) + for i, fcr := range txn.FileContractRevisions { + replaceEphemeral(types.Hash256(fcr.Parent.ID), &txn.FileContractRevisions[i].Parent.StateElement) } - for i := range txn.FileContractResolutions { - replaceEphemeral(&txn.FileContractResolutions[i].Parent.StateElement) + for i, fcr := range txn.FileContractResolutions { + replaceEphemeral(types.Hash256(fcr.Parent.ID), &txn.FileContractResolutions[i].Parent.StateElement) } } @@ -724,48 +724,48 @@ func (m *Manager) revertPoolUpdate(cru consensus.RevertUpdate, cs consensus.Stat func (m *Manager) applyPoolUpdate(cau consensus.ApplyUpdate, cs consensus.State) { // applying a block can make ephemeral elements in the txpool non-ephemeral var newElements map[types.Hash256]types.StateElement - replaceEphemeral := func(e *types.StateElement) { + replaceEphemeral := func(id types.Hash256, e *types.StateElement) { if e.LeafIndex != types.UnassignedLeafIndex { return } else if newElements == nil { newElements = make(map[types.Hash256]types.StateElement) cau.ForEachSiacoinElement(func(sce types.SiacoinElement, created, spent bool) { if created { - newElements[sce.ID] = sce.StateElement + newElements[types.Hash256(sce.ID)] = sce.StateElement } }) cau.ForEachSiafundElement(func(sfe types.SiafundElement, created, spent bool) { if created { - newElements[sfe.ID] = sfe.StateElement + newElements[types.Hash256(sfe.ID)] = sfe.StateElement } }) cau.ForEachFileContractElement(func(fce types.FileContractElement, created bool, rev *types.FileContractElement, resolved, valid bool) { if created { - newElements[fce.ID] = fce.StateElement + newElements[types.Hash256(fce.ID)] = fce.StateElement } }) cau.ForEachV2FileContractElement(func(fce types.V2FileContractElement, created bool, rev *types.V2FileContractElement, res types.V2FileContractResolutionType) { if created { - newElements[fce.ID] = fce.StateElement + newElements[types.Hash256(fce.ID)] = fce.StateElement } }) } - if se, ok := newElements[e.ID]; ok { + if se, ok := newElements[id]; ok { *e = se } } for _, txn := range m.txpool.v2txns { - for i := range txn.SiacoinInputs { - replaceEphemeral(&txn.SiacoinInputs[i].Parent.StateElement) + for i, si := range txn.SiacoinInputs { + replaceEphemeral(types.Hash256(si.Parent.ID), &txn.SiacoinInputs[i].Parent.StateElement) } - for i := range txn.SiafundInputs { - replaceEphemeral(&txn.SiafundInputs[i].Parent.StateElement) + for i, si := range txn.SiafundInputs { + replaceEphemeral(types.Hash256(si.Parent.ID), &txn.SiafundInputs[i].Parent.StateElement) } - for i := range txn.FileContractRevisions { - replaceEphemeral(&txn.FileContractRevisions[i].Parent.StateElement) + for i, fcr := range txn.FileContractRevisions { + replaceEphemeral(types.Hash256(fcr.Parent.ID), &txn.FileContractRevisions[i].Parent.StateElement) } - for i := range txn.FileContractResolutions { - replaceEphemeral(&txn.FileContractResolutions[i].Parent.StateElement) + for i, fcr := range txn.FileContractResolutions { + replaceEphemeral(types.Hash256(fcr.Parent.ID), &txn.FileContractResolutions[i].Parent.StateElement) } } @@ -1082,12 +1082,12 @@ func (m *Manager) updateV2TransactionProofs(txns []types.V2Transaction, from, to confirmedStateElements := make(map[types.Hash256]types.StateElement) cau.ForEachSiacoinElement(func(sce types.SiacoinElement, created, spent bool) { if created { - confirmedStateElements[sce.ID] = sce.StateElement + confirmedStateElements[types.Hash256(sce.ID)] = sce.StateElement } }) cau.ForEachSiafundElement(func(sfe types.SiafundElement, created, spent bool) { if created { - confirmedStateElements[sfe.ID] = sfe.StateElement + confirmedStateElements[types.Hash256(sfe.ID)] = sfe.StateElement } }) @@ -1100,7 +1100,7 @@ func (m *Manager) updateV2TransactionProofs(txns []types.V2Transaction, from, to // update the state elements for any confirmed ephemeral elements for j := range txns[i].SiacoinInputs { - if txns[i].SiacoinInputs[j].Parent.LeafIndex != types.UnassignedLeafIndex { + if txns[i].SiacoinInputs[j].Parent.StateElement.LeafIndex != types.UnassignedLeafIndex { continue } se, ok := confirmedStateElements[types.Hash256(txns[i].SiacoinInputs[j].Parent.ID)] @@ -1112,7 +1112,7 @@ func (m *Manager) updateV2TransactionProofs(txns []types.V2Transaction, from, to // update the state elements for any confirmed ephemeral elements for j := range txns[i].SiafundInputs { - if txns[i].SiafundInputs[j].Parent.LeafIndex != types.UnassignedLeafIndex { + if txns[i].SiafundInputs[j].Parent.StateElement.LeafIndex != types.UnassignedLeafIndex { continue } se, ok := confirmedStateElements[types.Hash256(txns[i].SiafundInputs[j].Parent.ID)] diff --git a/miner_test.go b/miner_test.go index 8f5b47c..8894958 100644 --- a/miner_test.go +++ b/miner_test.go @@ -105,7 +105,7 @@ func TestV2MineBlocks(t *testing.T) { // mine until just before the allow height mineBlocks(t, 4) - elements := make(map[types.Hash256]types.SiacoinElement) + elements := make(map[types.SiacoinOutputID]types.SiacoinElement) _, applied, err := cm.UpdatesSince(types.ChainIndex{}, 500) if err != nil { t.Fatal(err) diff --git a/rhp/v4/rpc.go b/rhp/v4/rpc.go index 740d206..93d5973 100644 --- a/rhp/v4/rpc.go +++ b/rhp/v4/rpc.go @@ -659,12 +659,9 @@ func RPCRenewContract(ctx context.Context, t TransportClient, tp TxPool, signer FileContractResolutions: []types.V2FileContractResolution{ { Parent: types.V2FileContractElement{ - StateElement: types.StateElement{ - // the other parts of the state element are not required - // for signing the transaction. Let the host fill them - // in. - ID: types.Hash256(params.ContractID), - }, + ID: params.ContractID, + // the state element field is not required for signing the + // transaction. The host will fill it in. }, Resolution: &renewal, }, @@ -787,12 +784,9 @@ func RPCRefreshContract(ctx context.Context, t TransportClient, tp TxPool, signe FileContractResolutions: []types.V2FileContractResolution{ { Parent: types.V2FileContractElement{ - StateElement: types.StateElement{ - // the other parts of the state element are not required - // for signing the transaction. Let the host fill them - // in. - ID: types.Hash256(params.ContractID), - }, + ID: params.ContractID, + // the state element field is not required for signing the + // transaction. The host will fill it in. }, Resolution: &renewal, }, diff --git a/testutil/wallet.go b/testutil/wallet.go index 11cb385..e5f6094 100644 --- a/testutil/wallet.go +++ b/testutil/wallet.go @@ -33,14 +33,13 @@ func (et *ephemeralWalletUpdateTxn) WalletStateElements() (elements []types.Stat return } -func (et *ephemeralWalletUpdateTxn) UpdateWalletStateElements(elements []types.StateElement) error { - for _, se := range elements { - utxo, ok := et.store.utxos[types.SiacoinOutputID(se.ID)] - if !ok { - panic(fmt.Sprintf("siacoin element %q does not exist", se.ID)) - } - utxo.StateElement = se - et.store.utxos[types.SiacoinOutputID(se.ID)] = utxo +// UpdateWalletSiacoinElementProofs updates the proofs of all state elements +// affected by the update. ProofUpdater.UpdateElementProof must be called +// for each state element in the database. +func (et *ephemeralWalletUpdateTxn) UpdateWalletSiacoinElementProofs(pu wallet.ProofUpdater) error { + for _, se := range et.store.utxos { + pu.UpdateElementProof(&se.StateElement) + et.store.utxos[se.ID] = se } return nil } @@ -131,7 +130,7 @@ func (es *EphemeralWalletStore) UnspentSiacoinElements() (utxos []types.SiacoinE defer es.mu.Unlock() for _, se := range es.utxos { - se.MerkleProof = append([]types.Hash256(nil), se.MerkleProof...) + se.StateElement.MerkleProof = append([]types.Hash256(nil), se.StateElement.MerkleProof...) utxos = append(utxos, se) } return utxos, nil diff --git a/wallet/events.go b/wallet/events.go index 3ad5579..9116bd5 100644 --- a/wallet/events.go +++ b/wallet/events.go @@ -276,3 +276,126 @@ func (e *Event) UnmarshalJSON(b []byte) error { } return err } + +// EncodeTo implements types.EncoderTo +func (ep EventPayout) EncodeTo(e *types.Encoder) { + ep.SiacoinElement.EncodeTo(e) +} + +// DecodeFrom implements types.DecoderFrom +func (ep *EventPayout) DecodeFrom(d *types.Decoder) { + ep.SiacoinElement.DecodeFrom(d) +} + +// EncodeTo implements types.EncoderTo +func (et EventV1Transaction) EncodeTo(e *types.Encoder) { + et.Transaction.EncodeTo(e) + types.EncodeSlice(e, et.SpentSiacoinElements) + types.EncodeSlice(e, et.SpentSiafundElements) +} + +// DecodeFrom implements types.DecoderFrom +func (et *EventV1Transaction) DecodeFrom(d *types.Decoder) { + et.Transaction.DecodeFrom(d) + types.DecodeSlice(d, &et.SpentSiacoinElements) + types.DecodeSlice(d, &et.SpentSiafundElements) +} + +// EncodeTo implements types.EncoderTo +func (et EventV2Transaction) EncodeTo(e *types.Encoder) { + types.V2Transaction(et).EncodeTo(e) +} + +// DecodeFrom implements types.DecoderFrom +func (et *EventV2Transaction) DecodeFrom(d *types.Decoder) { + (*types.V2Transaction)(et).DecodeFrom(d) +} + +// EncodeTo implements types.EncoderTo +func (er EventV1ContractResolution) EncodeTo(e *types.Encoder) { + er.Parent.EncodeTo(e) + er.SiacoinElement.EncodeTo(e) + e.WriteBool(er.Missed) +} + +// DecodeFrom implements types.DecoderFrom +func (er *EventV1ContractResolution) DecodeFrom(d *types.Decoder) { + er.Parent.DecodeFrom(d) + er.SiacoinElement.DecodeFrom(d) + er.Missed = d.ReadBool() +} + +// EncodeTo implements types.EncoderTo +func (er EventV2ContractResolution) EncodeTo(e *types.Encoder) { + er.Resolution.EncodeTo(e) + er.SiacoinElement.EncodeTo(e) + e.WriteBool(er.Missed) +} + +// DecodeFrom implements types.DecoderFrom +func (er *EventV2ContractResolution) DecodeFrom(d *types.Decoder) { + er.Resolution.DecodeFrom(d) + er.SiacoinElement.DecodeFrom(d) + er.Missed = d.ReadBool() +} + +// EncodeTo implements types.EncoderTo +func (ev *Event) EncodeTo(e *types.Encoder) { + ev.ID.EncodeTo(e) + ev.Index.EncodeTo(e) + e.WriteUint64(ev.Confirmations) + e.WriteString(ev.Type) + switch data := ev.Data.(type) { + case EventPayout: + data.EncodeTo(e) + case EventV1Transaction: + data.EncodeTo(e) + case EventV1ContractResolution: + data.EncodeTo(e) + case EventV2ContractResolution: + data.EncodeTo(e) + case EventV2Transaction: + types.V2Transaction(data).EncodeTo(e) + default: + panic("unknown event type") // should never happen + } + e.WriteUint64(ev.MaturityHeight) + e.WriteTime(ev.Timestamp) + types.EncodeSlice(e, ev.Relevant) +} + +// DecodeFrom implements types.DecoderFrom +func (ev *Event) DecodeFrom(d *types.Decoder) { + ev.ID.DecodeFrom(d) + ev.Index.DecodeFrom(d) + ev.Confirmations = d.ReadUint64() + ev.Type = d.ReadString() + switch ev.Type { + case EventTypeMinerPayout, EventTypeFoundationSubsidy, EventTypeSiafundClaim: + var data EventPayout + data.DecodeFrom(d) + ev.Data = data + case EventTypeV1Transaction: + var data EventV1Transaction + data.DecodeFrom(d) + ev.Data = data + case EventTypeV1ContractResolution: + var data EventV1ContractResolution + data.DecodeFrom(d) + ev.Data = data + case EventTypeV2ContractResolution: + var data EventV2ContractResolution + data.DecodeFrom(d) + ev.Data = data + case EventTypeV2Transaction: + var data types.V2Transaction + data.DecodeFrom(d) + ev.Data = EventV2Transaction(data) + default: + d.SetErr(fmt.Errorf("unknown event type: %q", ev.Type)) + return + } + ev.MaturityHeight = d.ReadUint64() + ev.Timestamp = d.ReadTime() + types.DecodeSlice(d, &ev.Relevant) +} diff --git a/wallet/update.go b/wallet/update.go index f19b07b..eb474b7 100644 --- a/wallet/update.go +++ b/wallet/update.go @@ -18,15 +18,18 @@ type ( ForEachV2FileContractElement(func(fce types.V2FileContractElement, rev *types.V2FileContractElement, res types.V2FileContractResolutionType)) } + // A ProofUpdater is an interface for updating the proof of a state element. + ProofUpdater interface { + UpdateElementProof(e *types.StateElement) + } + // UpdateTx is an interface for atomically applying chain updates to a // single address wallet. UpdateTx interface { - // WalletStateElements returns all state elements related to the wallet. It is used - // to update the proofs of all state elements affected by the update. - WalletStateElements() ([]types.StateElement, error) - // UpdateWalletStateElements updates the proofs of all state elements affected by the - // update. - UpdateWalletStateElements([]types.StateElement) error + // UpdateWalletSiacoinElementProofs updates the proofs of all state elements + // affected by the update. ProofUpdater.UpdateElementProof must be called + // for each state element in the database. + UpdateWalletSiacoinElementProofs(ProofUpdater) error // WalletApplyIndex is called with the chain index that is being applied. // Any transactions and siacoin elements that were created by the index @@ -89,7 +92,7 @@ func appliedEvents(cau chain.ApplyUpdate, walletAddress types.Address) (events [ // cache the value of siacoin elements to use when calculating v1 outflow cau.ForEachSiacoinElement(func(se types.SiacoinElement, created, spent bool) { - se.MerkleProof = nil // clear the proof to save space + se.StateElement.MerkleProof = nil // clear the proof to save space siacoinElements[types.SiacoinOutputID(se.ID)] = se }) @@ -172,7 +175,7 @@ func appliedEvents(cau chain.ApplyUpdate, walletAddress types.Address) (events [ return } - fce.MerkleProof = nil // clear the proof to save space + fce.StateElement.MerkleProof = nil // clear the proof to save space if valid { for i, so := range fce.FileContract.ValidProofOutputs { @@ -223,7 +226,7 @@ func appliedEvents(cau chain.ApplyUpdate, walletAddress types.Address) (events [ missed = true } - fce.MerkleProof = nil // clear the proof to save space + fce.StateElement.MerkleProof = nil // clear the proof to save space if fce.V2FileContract.HostOutput.Address == walletAddress { outputID := types.FileContractID(fce.ID).V2HostOutputID() @@ -291,15 +294,7 @@ func (sw *SingleAddressWallet) applyChainUpdate(tx UpdateTx, address types.Addre defer sw.mu.Unlock() // update current state elements - stateElements, err := tx.WalletStateElements() - if err != nil { - return fmt.Errorf("failed to get state elements: %w", err) - } - - for i := range stateElements { - cau.UpdateElementProof(&stateElements[i]) - } - if err := tx.UpdateWalletStateElements(stateElements); err != nil { + if err := tx.UpdateWalletSiacoinElementProofs(cau); err != nil { return fmt.Errorf("failed to update state elements: %w", err) } @@ -357,14 +352,7 @@ func (sw *SingleAddressWallet) revertChainUpdate(tx UpdateTx, revertedIndex type } // update the remaining state elements - stateElements, err := tx.WalletStateElements() - if err != nil { - return fmt.Errorf("failed to get state elements: %w", err) - } - for i := range stateElements { - cru.UpdateElementProof(&stateElements[i]) - } - if err := tx.UpdateWalletStateElements(stateElements); err != nil { + if err := tx.UpdateWalletSiacoinElementProofs(cru); err != nil { return fmt.Errorf("failed to update state elements: %w", err) } sw.tip = revertedIndex diff --git a/wallet/wallet.go b/wallet/wallet.go index 33c26be..7f24352 100644 --- a/wallet/wallet.go +++ b/wallet/wallet.go @@ -81,7 +81,7 @@ type ( // locked is a set of siacoin output IDs locked by FundTransaction. They // will be released either by calling Release for unused transactions or // being confirmed in a block. - locked map[types.Hash256]time.Time + locked map[types.SiacoinOutputID]time.Time } ) @@ -116,12 +116,12 @@ func (sw *SingleAddressWallet) Balance() (balance Balance, err error) { return Balance{}, fmt.Errorf("failed to get unspent outputs: %w", err) } - tpoolSpent := make(map[types.Hash256]bool) - tpoolUtxos := make(map[types.Hash256]types.SiacoinElement) + tpoolSpent := make(map[types.SiacoinOutputID]bool) + tpoolUtxos := make(map[types.SiacoinOutputID]types.SiacoinElement) for _, txn := range sw.cm.PoolTransactions() { for _, sci := range txn.SiacoinInputs { - tpoolSpent[types.Hash256(sci.ParentID)] = true - delete(tpoolUtxos, types.Hash256(sci.ParentID)) + tpoolSpent[sci.ParentID] = true + delete(tpoolUtxos, sci.ParentID) } for i, sco := range txn.SiacoinOutputs { if sco.Address != sw.addr { @@ -129,10 +129,9 @@ func (sw *SingleAddressWallet) Balance() (balance Balance, err error) { } outputID := txn.SiacoinOutputID(i) - tpoolUtxos[types.Hash256(outputID)] = types.SiacoinElement{ - StateElement: types.StateElement{ - ID: types.Hash256(types.SiacoinOutputID(outputID)), - }, + tpoolUtxos[outputID] = types.SiacoinElement{ + ID: types.SiacoinOutputID(outputID), + StateElement: types.StateElement{LeafIndex: types.UnassignedLeafIndex}, SiacoinOutput: sco, } } @@ -140,8 +139,8 @@ func (sw *SingleAddressWallet) Balance() (balance Balance, err error) { for _, txn := range sw.cm.V2PoolTransactions() { for _, si := range txn.SiacoinInputs { - tpoolSpent[types.Hash256(si.Parent.ID)] = true - delete(tpoolUtxos, types.Hash256(si.Parent.ID)) + tpoolSpent[si.Parent.ID] = true + delete(tpoolUtxos, si.Parent.ID) } for i, sco := range txn.SiacoinOutputs { if sco.Address != sw.addr { @@ -194,10 +193,10 @@ func (sw *SingleAddressWallet) SpendableOutputs() ([]types.SiacoinElement, error } // fetch outputs currently in the pool - inPool := make(map[types.Hash256]bool) + inPool := make(map[types.SiacoinOutputID]bool) for _, txn := range sw.cm.PoolTransactions() { for _, sci := range txn.SiacoinInputs { - inPool[types.Hash256(sci.ParentID)] = true + inPool[sci.ParentID] = true } } @@ -229,26 +228,25 @@ func (sw *SingleAddressWallet) selectUTXOs(amount types.Currency, inputs int, us return nil, types.ZeroCurrency, err } - tpoolSpent := make(map[types.Hash256]bool) - tpoolUtxos := make(map[types.Hash256]types.SiacoinElement) + tpoolSpent := make(map[types.SiacoinOutputID]bool) + tpoolUtxos := make(map[types.SiacoinOutputID]types.SiacoinElement) for _, txn := range sw.cm.PoolTransactions() { for _, sci := range txn.SiacoinInputs { - tpoolSpent[types.Hash256(sci.ParentID)] = true - delete(tpoolUtxos, types.Hash256(sci.ParentID)) + tpoolSpent[sci.ParentID] = true + delete(tpoolUtxos, sci.ParentID) } for i, sco := range txn.SiacoinOutputs { - tpoolUtxos[types.Hash256(txn.SiacoinOutputID(i))] = types.SiacoinElement{ - StateElement: types.StateElement{ - ID: types.Hash256(types.SiacoinOutputID(txn.SiacoinOutputID(i))), - }, + tpoolUtxos[txn.SiacoinOutputID(i)] = types.SiacoinElement{ + ID: txn.SiacoinOutputID(i), + StateElement: types.StateElement{LeafIndex: types.UnassignedLeafIndex}, SiacoinOutput: sco, } } } for _, txn := range sw.cm.V2PoolTransactions() { for _, sci := range txn.SiacoinInputs { - tpoolSpent[types.Hash256(sci.Parent.ID)] = true - delete(tpoolUtxos, types.Hash256(sci.Parent.ID)) + tpoolSpent[sci.Parent.ID] = true + delete(tpoolUtxos, sci.Parent.ID) } for i := range txn.SiacoinOutputs { sce := txn.EphemeralSiacoinOutput(i) @@ -491,9 +489,9 @@ func (sw *SingleAddressWallet) UnconfirmedEvents() (annotated []Event, err error return nil, fmt.Errorf("failed to get unspent outputs: %w", err) } - utxos := make(map[types.Hash256]types.SiacoinElement) + utxos := make(map[types.SiacoinOutputID]types.SiacoinElement) for _, se := range confirmed { - utxos[types.Hash256(se.ID)] = se + utxos[se.ID] = se } index := types.ChainIndex{ @@ -526,7 +524,7 @@ func (sw *SingleAddressWallet) UnconfirmedEvents() (annotated []Event, err error var outflow types.Currency for _, sci := range txn.SiacoinInputs { - sce, ok := utxos[types.Hash256(sci.ParentID)] + sce, ok := utxos[sci.ParentID] if !ok { // ignore inputs that don't belong to the wallet continue @@ -540,8 +538,8 @@ func (sw *SingleAddressWallet) UnconfirmedEvents() (annotated []Event, err error if so.Address == sw.addr { inflow = inflow.Add(so.Value) sce := types.SiacoinElement{ + ID: txn.SiacoinOutputID(i), StateElement: types.StateElement{ - ID: types.Hash256(txn.SiacoinOutputID(i)), LeafIndex: types.UnassignedLeafIndex, }, SiacoinOutput: so, @@ -591,15 +589,15 @@ func (sw *SingleAddressWallet) selectRedistributeUTXOs(bh uint64, outputs int, a } // fetch outputs currently in the pool - inPool := make(map[types.Hash256]bool) + inPool := make(map[types.SiacoinOutputID]bool) for _, txn := range sw.cm.PoolTransactions() { for _, sci := range txn.SiacoinInputs { - inPool[types.Hash256(sci.ParentID)] = true + inPool[sci.ParentID] = true } } for _, txn := range sw.cm.V2PoolTransactions() { for _, sci := range txn.SiacoinInputs { - inPool[types.Hash256(sci.Parent.ID)] = true + inPool[sci.Parent.ID] = true } } @@ -650,7 +648,7 @@ func (sw *SingleAddressWallet) Redistribute(outputs int, amount, feePerByte type defer func() { if err != nil { for _, id := range toSign { - delete(sw.locked, id) + delete(sw.locked, types.SiacoinOutputID(id)) } } }() @@ -712,7 +710,7 @@ func (sw *SingleAddressWallet) Redistribute(outputs int, amount, feePerByte type ParentID: types.SiacoinOutputID(sce.ID), UnlockConditions: types.StandardUnlockConditions(sw.priv.PublicKey()), }) - toSign = append(toSign, sce.ID) + toSign = append(toSign, types.Hash256(sce.ID)) sw.locked[sce.ID] = time.Now().Add(sw.cfg.ReservationDuration) } txns = append(txns, txn) @@ -819,7 +817,7 @@ func (sw *SingleAddressWallet) ReleaseInputs(txns []types.Transaction, v2txns [] defer sw.mu.Unlock() for _, txn := range txns { for _, in := range txn.SiacoinInputs { - delete(sw.locked, types.Hash256(in.ParentID)) + delete(sw.locked, in.ParentID) } } for _, txn := range v2txns { @@ -831,7 +829,7 @@ func (sw *SingleAddressWallet) ReleaseInputs(txns []types.Transaction, v2txns [] // isLocked returns true if the siacoin output with given id is locked, this // method must be called whilst holding the mutex lock. -func (sw *SingleAddressWallet) isLocked(id types.Hash256) bool { +func (sw *SingleAddressWallet) isLocked(id types.SiacoinOutputID) bool { return time.Now().Before(sw.locked[id]) } @@ -939,7 +937,7 @@ func NewSingleAddressWallet(priv types.PrivateKey, cm ChainManager, store Single addr: types.StandardUnlockHash(priv.PublicKey()), tip: tip, - locked: make(map[types.Hash256]time.Time), + locked: make(map[types.SiacoinOutputID]time.Time), } return sw, nil }