From e2a559e2435a0629164f69142274c9a131afc24b Mon Sep 17 00:00:00 2001
From: Zilog8 <zeuscoding@gmail.com>
Date: Tue, 8 Jun 2021 01:45:35 -0400
Subject: [PATCH] Allow Storage Backends to do their own Hashing (#518)

* Allow Storage Backends to do their own Hashing

- Describes an optional interface 'SelfHashing' that a storage backend's type implementing 'PieceImpl' may also implement in order to calculate piece hashsums itself.

- Alters the 'hashPiece' function in the torrent package to look for types implementing 'SelfHashing' . If not implemented, calculate the hash as usual.
---
 storage/interface.go | 10 ++++++++--
 torrent.go           | 12 +++++++++++-
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/storage/interface.go b/storage/interface.go
index 869556f8..584338cb 100644
--- a/storage/interface.go
+++ b/storage/interface.go
@@ -22,8 +22,9 @@ type TorrentImpl interface {
 	Close() error
 }
 
-// Interacts with torrent piece data. Optional interfaces to implement include io.WriterTo, such as
-// when a piece supports a more efficient way to write out incomplete chunks
+// Interacts with torrent piece data. Optional interfaces to implement include:
+//   io.WriterTo, such as when a piece supports a more efficient way to write out incomplete chunks.
+//   SelfHashing, such as when a piece supports a more efficient way to hash its contents.
 type PieceImpl interface {
 	// These interfaces are not as strict as normally required. They can
 	// assume that the parameters are appropriate for the dimensions of the
@@ -43,3 +44,8 @@ type Completion struct {
 	Complete bool
 	Ok       bool
 }
+
+// Allows a storage backend to override hashing (i.e. if it can do it more efficiently than the torrent client can)
+type SelfHashing interface {
+	SelfHash() (metainfo.Hash, error)
+}
diff --git a/torrent.go b/torrent.go
index e3876474..82b70c13 100644
--- a/torrent.go
+++ b/torrent.go
@@ -810,10 +810,20 @@ func (t *Torrent) pieceLength(piece pieceIndex) pp.Integer {
 }
 
 func (t *Torrent) hashPiece(piece pieceIndex) (ret metainfo.Hash, err error) {
-	hash := pieceHash.New()
 	p := t.piece(piece)
 	p.waitNoPendingWrites()
 	storagePiece := t.pieces[piece].Storage()
+
+	//Does the backend want to do its own hashing?
+	if i, ok := storagePiece.PieceImpl.(storage.SelfHashing); ok {
+		var sum metainfo.Hash
+		//log.Printf("A piece decided to self-hash: %d", piece)
+		sum, err = i.SelfHash()
+		missinggo.CopyExact(&ret, sum)
+		return
+	}
+
+	hash := pieceHash.New()
 	const logPieceContents = false
 	if logPieceContents {
 		var examineBuf bytes.Buffer
-- 
2.51.0