@@ -10,16 +10,18 @@ const Protomux = require('protomux')
10
10
const z32 = require ( 'z32' )
11
11
const id = require ( 'hypercore-id-encoding' )
12
12
const safetyCatch = require ( 'safety-catch' )
13
+ const { createTracer } = require ( 'hypertrace' )
13
14
14
15
const Replicator = require ( './lib/replicator' )
15
16
const Core = require ( './lib/core' )
16
17
const BlockEncryption = require ( './lib/block-encryption' )
17
18
const Info = require ( './lib/info' )
18
19
const Download = require ( './lib/download' )
19
20
const Batch = require ( './lib/batch' )
20
- const { manifestHash, defaultSignerManifest, createVerifier , createManifest, isCompat } = require ( './lib/manifest ' )
21
+ const { manifestHash, defaultSignerManifest, createManifest, isCompat, sign } = require ( './lib/verifier ' )
21
22
const { ReadStream, WriteStream, ByteStream } = require ( './lib/streams' )
22
23
const {
24
+ ASSERTION ,
23
25
BAD_ARGUMENT ,
24
26
SESSION_CLOSED ,
25
27
SESSION_NOT_WRITABLE ,
@@ -29,6 +31,10 @@ const {
29
31
const promises = Symbol . for ( 'hypercore.promises' )
30
32
const inspect = Symbol . for ( 'nodejs.util.inspect.custom' )
31
33
34
+ // Hypercore actually does not have any notion of max/min block sizes
35
+ // but we enforce 15mb to ensure smooth replication (each block is transmitted atomically)
36
+ const MAX_SUGGESTED_BLOCK_SIZE = 15 * 1024 * 1024
37
+
32
38
module . exports = class Hypercore extends EventEmitter {
33
39
constructor ( storage , key , opts ) {
34
40
super ( )
@@ -49,6 +55,7 @@ module.exports = class Hypercore extends EventEmitter {
49
55
50
56
this [ promises ] = true
51
57
58
+ this . tracer = createTracer ( this )
52
59
this . storage = null
53
60
this . crypto = opts . crypto || hypercoreCrypto
54
61
this . core = null
@@ -133,8 +140,10 @@ module.exports = class Hypercore extends EventEmitter {
133
140
indent + ')'
134
141
}
135
142
143
+ static MAX_SUGGESTED_BLOCK_SIZE = MAX_SUGGESTED_BLOCK_SIZE
144
+
136
145
static key ( manifest , { compat } = { } ) {
137
- return compat ? manifest . signer . publicKey : manifestHash ( createManifest ( manifest ) )
146
+ return compat ? manifest . signers [ 0 ] . publicKey : manifestHash ( createManifest ( manifest ) )
138
147
}
139
148
140
149
static discoveryKey ( key ) {
@@ -267,6 +276,8 @@ module.exports = class Hypercore extends EventEmitter {
267
276
this . writable = this . _isWritable ( )
268
277
this . autoClose = o . autoClose
269
278
279
+ if ( o . core ) this . tracer . setParent ( o . core . tracer )
280
+
270
281
if ( this . snapshotted && this . core && ! this . _snapshot ) this . _updateSnapshot ( )
271
282
}
272
283
@@ -377,6 +388,7 @@ module.exports = class Hypercore extends EventEmitter {
377
388
onupdate : this . _oncoreupdate . bind ( this ) ,
378
389
onconflict : this . _oncoreconflict . bind ( this )
379
390
} )
391
+ this . tracer . setParent ( this . core . tracer )
380
392
381
393
if ( opts . userData ) {
382
394
for ( const [ key , value ] of Object . entries ( opts . userData ) ) {
@@ -490,14 +502,14 @@ module.exports = class Hypercore extends EventEmitter {
490
502
}
491
503
492
504
const manifest = opts . manifest || defaultSignerManifest ( keyPair . publicKey )
493
- const key = opts . key || ( opts . compat !== false ? manifest . signer . publicKey : manifestHash ( manifest ) )
505
+ const key = opts . key || ( opts . compat !== false ? manifest . signers [ 0 ] . publicKey : manifestHash ( manifest ) )
494
506
495
507
if ( b4a . equals ( key , this . key ) ) {
496
508
throw BAD_ARGUMENT ( 'Clone cannot share verification information' )
497
509
}
498
510
499
511
const signature = opts . signature === undefined
500
- ? createVerifier ( createManifest ( manifest ) , { compat : isCompat ( key , manifest ) } ) . sign ( this . core . tree . batch ( ) , keyPair )
512
+ ? sign ( createManifest ( manifest ) , this . core . tree . batch ( ) , keyPair , { compat : isCompat ( key , manifest ) } )
501
513
: opts . signature
502
514
503
515
const sparse = opts . sparse === false ? false : this . sparse
@@ -809,12 +821,13 @@ module.exports = class Hypercore extends EventEmitter {
809
821
return true
810
822
}
811
823
812
- batch ( { checkout = - 1 , autoClose = true , session = true , restore = false } = { } ) {
813
- return new Batch ( session ? this . session ( ) : this , checkout , autoClose , restore )
824
+ batch ( { checkout = - 1 , autoClose = true , session = true , restore = false , clear = false } = { } ) {
825
+ return new Batch ( session ? this . session ( ) : this , checkout , autoClose , restore , clear )
814
826
}
815
827
816
828
async seek ( bytes , opts ) {
817
829
if ( this . opened === false ) await this . opening
830
+ if ( ! isValidIndex ( bytes ) ) throw ASSERTION ( 'seek is invalid' )
818
831
819
832
const tree = ( opts && opts . tree ) || this . core . tree
820
833
const s = tree . seek ( bytes , this . padding )
@@ -837,17 +850,20 @@ module.exports = class Hypercore extends EventEmitter {
837
850
838
851
async has ( start , end = start + 1 ) {
839
852
if ( this . opened === false ) await this . opening
853
+ if ( ! isValidIndex ( start ) || ! isValidIndex ( end ) ) throw ASSERTION ( 'has range is invalid' )
840
854
841
- const length = end - start
842
- if ( length <= 0 ) return false
843
- if ( length === 1 ) return this . core . bitfield . get ( start )
855
+ if ( end === start + 1 ) return this . core . bitfield . get ( start )
844
856
845
857
const i = this . core . bitfield . firstUnset ( start )
846
858
return i === - 1 || i >= end
847
859
}
848
860
849
861
async get ( index , opts ) {
850
862
if ( this . opened === false ) await this . opening
863
+ if ( ! isValidIndex ( index ) ) throw ASSERTION ( 'block index is invalid' )
864
+
865
+ this . tracer . trace ( 'get' , { index } )
866
+
851
867
if ( this . closing !== null ) throw SESSION_CLOSED ( )
852
868
if ( this . _snapshot !== null && index >= this . _snapshot . compatLength ) throw SNAPSHOT_NOT_AVAILABLE ( )
853
869
@@ -878,6 +894,8 @@ module.exports = class Hypercore extends EventEmitter {
878
894
end = start + 1
879
895
}
880
896
897
+ if ( ! isValidIndex ( start ) || ! isValidIndex ( end ) ) throw ASSERTION ( 'clear range is invalid' )
898
+
881
899
const cleared = ( opts && opts . diff ) ? { blocks : 0 } : null
882
900
883
901
if ( start >= end ) return cleared
@@ -910,6 +928,7 @@ module.exports = class Hypercore extends EventEmitter {
910
928
const activeRequests = ( opts && opts . activeRequests ) || this . activeRequests
911
929
912
930
const req = this . replicator . addBlock ( activeRequests , index )
931
+ req . snapshot = index < this . length
913
932
914
933
const timeout = opts && opts . timeout !== undefined ? opts . timeout : this . timeout
915
934
if ( timeout ) req . context . setTimeout ( req , timeout )
@@ -962,6 +981,8 @@ module.exports = class Hypercore extends EventEmitter {
962
981
async _download ( range ) {
963
982
if ( this . opened === false ) await this . opening
964
983
984
+ this . tracer . trace ( 'download' , { range } )
985
+
965
986
const activeRequests = ( range && range . activeRequests ) || this . activeRequests
966
987
967
988
return this . replicator . addRange ( activeRequests , range )
@@ -1004,6 +1025,7 @@ module.exports = class Hypercore extends EventEmitter {
1004
1025
if ( writable === false ) throw SESSION_NOT_WRITABLE ( )
1005
1026
1006
1027
blocks = Array . isArray ( blocks ) ? blocks : [ blocks ]
1028
+ this . tracer . trace ( 'append' , { blocks } )
1007
1029
1008
1030
const preappend = this . encryption && this . _preappend
1009
1031
@@ -1014,6 +1036,11 @@ module.exports = class Hypercore extends EventEmitter {
1014
1036
buffers [ i ] = this . _encode ( this . valueEncoding , blocks [ i ] )
1015
1037
}
1016
1038
}
1039
+ for ( const b of buffers ) {
1040
+ if ( b . byteLength > MAX_SUGGESTED_BLOCK_SIZE ) {
1041
+ throw BAD_ARGUMENT ( 'Appended block exceeds the maximum suggested block size' )
1042
+ }
1043
+ }
1017
1044
1018
1045
return this . core . append ( buffers , { keyPair, signature, preappend } )
1019
1046
}
@@ -1133,3 +1160,7 @@ function ensureEncryption (core, opts) {
1133
1160
function createCache ( cache ) {
1134
1161
return cache === true ? new Xache ( { maxSize : 65536 , maxAge : 0 } ) : ( cache || null )
1135
1162
}
1163
+
1164
+ function isValidIndex ( index ) {
1165
+ return index === 0 || index > 0
1166
+ }
0 commit comments