@bsv/sdk 1.2.7 → 1.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/src/overlay-tools/SHIPBroadcaster.js +2 -2
- package/dist/cjs/src/overlay-tools/SHIPBroadcaster.js.map +1 -1
- package/dist/cjs/src/primitives/PublicKey.js +6 -0
- package/dist/cjs/src/primitives/PublicKey.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/overlay-tools/SHIPBroadcaster.js +2 -2
- package/dist/esm/src/overlay-tools/SHIPBroadcaster.js.map +1 -1
- package/dist/esm/src/primitives/PublicKey.js +6 -0
- package/dist/esm/src/primitives/PublicKey.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/overlay-tools/SHIPBroadcaster.d.ts +9 -4
- package/dist/types/src/overlay-tools/SHIPBroadcaster.d.ts.map +1 -1
- package/dist/types/src/primitives/PublicKey.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +1 -1
- package/docs/overlay-tools.md +11 -1
- package/package.json +1 -1
- package/src/overlay-tools/SHIPBroadcaster.ts +13 -6
- package/src/overlay-tools/__tests/SHIPBroadcaster.test.ts +82 -0
- package/src/primitives/PublicKey.ts +6 -0
- package/src/primitives/__tests/PublicKey.test.ts +6 -0
package/docs/overlay-tools.md
CHANGED
|
@@ -26,6 +26,7 @@ Instructs the Overlay Services Engine about which outputs to admit and which pre
|
|
|
26
26
|
export interface AdmittanceInstructions {
|
|
27
27
|
outputsToAdmit: number[];
|
|
28
28
|
coinsToRetain: number[];
|
|
29
|
+
coinsRemoved?: number[];
|
|
29
30
|
}
|
|
30
31
|
```
|
|
31
32
|
|
|
@@ -33,6 +34,15 @@ export interface AdmittanceInstructions {
|
|
|
33
34
|
|
|
34
35
|
<summary>Interface AdmittanceInstructions Details</summary>
|
|
35
36
|
|
|
37
|
+
#### Property coinsRemoved
|
|
38
|
+
|
|
39
|
+
The indices of all inputs from the provided transaction which reference previously-admitted outputs,
|
|
40
|
+
which are now considered spent and have been removed from the managed topic.
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
coinsRemoved?: number[]
|
|
44
|
+
```
|
|
45
|
+
|
|
36
46
|
#### Property coinsToRetain
|
|
37
47
|
|
|
38
48
|
The indices of all inputs from the provided transaction which spend previously-admitted outputs that should be retained for historical record-keeping.
|
|
@@ -43,7 +53,7 @@ coinsToRetain: number[]
|
|
|
43
53
|
|
|
44
54
|
#### Property outputsToAdmit
|
|
45
55
|
|
|
46
|
-
The indices of all
|
|
56
|
+
The indices of all admissible outputs into the managed topic from the provided transaction.
|
|
47
57
|
|
|
48
58
|
```ts
|
|
49
59
|
outputsToAdmit: number[]
|
package/package.json
CHANGED
|
@@ -18,14 +18,20 @@ export interface TaggedBEEF {
|
|
|
18
18
|
*/
|
|
19
19
|
export interface AdmittanceInstructions {
|
|
20
20
|
/**
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
* The indices of all admissible outputs into the managed topic from the provided transaction.
|
|
22
|
+
*/
|
|
23
23
|
outputsToAdmit: number[]
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
* The indices of all inputs from the provided transaction which spend previously-admitted outputs that should be retained for historical record-keeping.
|
|
27
|
+
*/
|
|
28
28
|
coinsToRetain: number[]
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The indices of all inputs from the provided transaction which reference previously-admitted outputs,
|
|
32
|
+
* which are now considered spent and have been removed from the managed topic.
|
|
33
|
+
*/
|
|
34
|
+
coinsRemoved?: number[]
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
/**
|
|
@@ -180,8 +186,9 @@ export default class SHIPCast implements Broadcaster {
|
|
|
180
186
|
for (const [topic, instructions] of Object.entries(steak)) {
|
|
181
187
|
const outputsToAdmit = instructions.outputsToAdmit
|
|
182
188
|
const coinsToRetain = instructions.coinsToRetain
|
|
183
|
-
|
|
184
|
-
|
|
189
|
+
const coinsRemoved = instructions.coinsRemoved
|
|
190
|
+
|
|
191
|
+
if ((outputsToAdmit?.length > 0) || (coinsToRetain?.length > 0) || (coinsRemoved?.length > 0)) {
|
|
185
192
|
acknowledgedTopics.add(topic)
|
|
186
193
|
}
|
|
187
194
|
}
|
|
@@ -652,6 +652,88 @@ describe('SHIPCast', () => {
|
|
|
652
652
|
})
|
|
653
653
|
})
|
|
654
654
|
|
|
655
|
+
it('should succeed when interested hosts only remove coins in a transaction broadcast', async () => {
|
|
656
|
+
const shipHostKey1 = new PrivateKey(42)
|
|
657
|
+
const shipWallet1 = new ProtoWallet(shipHostKey1)
|
|
658
|
+
const shipLib1 = new OverlayAdminTokenTemplate(shipWallet1)
|
|
659
|
+
const shipScript1 = await shipLib1.lock('SHIP', 'https://shiphost1.com', 'tm_foo')
|
|
660
|
+
const shipTx1 = new Transaction(1, [], [{
|
|
661
|
+
lockingScript: shipScript1,
|
|
662
|
+
satoshis: 1
|
|
663
|
+
}], 0)
|
|
664
|
+
|
|
665
|
+
const shipHostKey2 = new PrivateKey(43)
|
|
666
|
+
const shipWallet2 = new ProtoWallet(shipHostKey2)
|
|
667
|
+
const shipLib2 = new OverlayAdminTokenTemplate(shipWallet2)
|
|
668
|
+
const shipScript2 = await shipLib2.lock('SHIP', 'https://shiphost2.com', 'tm_bar')
|
|
669
|
+
const shipTx2 = new Transaction(1, [], [{
|
|
670
|
+
lockingScript: shipScript2,
|
|
671
|
+
satoshis: 1
|
|
672
|
+
}], 0)
|
|
673
|
+
|
|
674
|
+
// Resolver returns two hosts
|
|
675
|
+
mockResolver.query.mockReturnValueOnce({
|
|
676
|
+
type: 'output-list',
|
|
677
|
+
outputs: [
|
|
678
|
+
{ beef: shipTx1.toBEEF(), outputIndex: 0 },
|
|
679
|
+
{ beef: shipTx2.toBEEF(), outputIndex: 0 }
|
|
680
|
+
]
|
|
681
|
+
})
|
|
682
|
+
|
|
683
|
+
// First host acknowledges 'tm_foo' with coinsRemoved
|
|
684
|
+
mockFacilitator.send.mockImplementationOnce(async (host, { beef, topics }) => {
|
|
685
|
+
const steak = {}
|
|
686
|
+
for (const topic of topics) {
|
|
687
|
+
steak[topic] = {
|
|
688
|
+
outputsToAdmit: [],
|
|
689
|
+
coinsToRetain: [],
|
|
690
|
+
coinsRemoved: topic === 'tm_foo' ? [0] : []
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
return steak
|
|
694
|
+
})
|
|
695
|
+
|
|
696
|
+
// Second host does not acknowledge 'tm_bar'
|
|
697
|
+
mockFacilitator.send.mockImplementationOnce(async (host, { beef, topics }) => {
|
|
698
|
+
const steak = {}
|
|
699
|
+
for (const topic of topics) {
|
|
700
|
+
steak[topic] = {
|
|
701
|
+
outputsToAdmit: [],
|
|
702
|
+
coinsToRetain: [],
|
|
703
|
+
coinsRemoved: []
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
return steak
|
|
707
|
+
})
|
|
708
|
+
|
|
709
|
+
const b = new SHIPCast(['tm_foo', 'tm_bar'], {
|
|
710
|
+
facilitator: mockFacilitator,
|
|
711
|
+
resolver: mockResolver as unknown as LookupResolver,
|
|
712
|
+
requireAcknowledgmentFromSpecificHostsForTopics: {
|
|
713
|
+
'https://shiphost1.com': ['tm_foo']
|
|
714
|
+
},
|
|
715
|
+
requireAcknowledgmentFromAllHostsForTopics: [],
|
|
716
|
+
requireAcknowledgmentFromAnyHostForTopics: []
|
|
717
|
+
})
|
|
718
|
+
|
|
719
|
+
const testTx = new Transaction(1, [], [], 0)
|
|
720
|
+
const response = await b.broadcast(testTx)
|
|
721
|
+
|
|
722
|
+
expect(response).toEqual({
|
|
723
|
+
status: 'success',
|
|
724
|
+
txid: testTx.id('hex'),
|
|
725
|
+
message: 'Sent to 2 Overlay Services hosts.'
|
|
726
|
+
})
|
|
727
|
+
|
|
728
|
+
// Verify the resolver was queried correctly
|
|
729
|
+
expect(mockResolver.query).toHaveBeenCalledWith({
|
|
730
|
+
service: 'ls_ship',
|
|
731
|
+
query: {
|
|
732
|
+
topics: ['tm_foo', 'tm_bar']
|
|
733
|
+
}
|
|
734
|
+
}, 1000)
|
|
735
|
+
})
|
|
736
|
+
|
|
655
737
|
it('should fail when specific hosts do not acknowledge required topics', async () => {
|
|
656
738
|
const shipHostKey1 = new PrivateKey(42)
|
|
657
739
|
const shipWallet1 = new ProtoWallet(shipHostKey1)
|
|
@@ -84,6 +84,12 @@ export default class PublicKey extends Point {
|
|
|
84
84
|
if (x instanceof Point) {
|
|
85
85
|
super(x.getX(), x.getY())
|
|
86
86
|
} else {
|
|
87
|
+
// Common gotcha: constructing PublicKey with a DER value when you should use .fromString()
|
|
88
|
+
if (y === null && isRed && typeof x === 'string') {
|
|
89
|
+
if (x.length === 66 || x.length === 130) {
|
|
90
|
+
throw new Error('You are using the "new PublicKey()" constructor with a DER hex string. You need to use "PublicKey.fromString()" instead.')
|
|
91
|
+
}
|
|
92
|
+
}
|
|
87
93
|
super(x, y, isRed)
|
|
88
94
|
}
|
|
89
95
|
}
|
|
@@ -27,6 +27,12 @@ describe('PublicKey', () => {
|
|
|
27
27
|
})
|
|
28
28
|
})
|
|
29
29
|
|
|
30
|
+
describe('Constructor', () => {
|
|
31
|
+
it('Should throw when accidentally passing in DER', () => {
|
|
32
|
+
expect(() => new PublicKey('036af279b60aa437d48bb0e2ec0b0c6b5cfaa976663f1f08ad456fd7fff149321d')).toThrow()
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
|
|
30
36
|
describe('Instance methods', () => {
|
|
31
37
|
test('deriveSharedSecret should derive a shared secret Point', () => {
|
|
32
38
|
const sharedSecret = publicKey.deriveSharedSecret(privateKey)
|