Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
duniter
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container Registry
Model registry
Monitor
Service Desk
Analyze
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
nodes
typescript
duniter
Commits
33735971
Commit
33735971
authored
7 years ago
by
Cédric Moreau
Browse files
Options
Downloads
Patches
Plain Diff
[fix]
#1037
Migrate global_rules
parent
982f8783
No related branches found
No related tags found
No related merge requests found
Changes
4
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
.eslintignore
+1
-0
1 addition, 0 deletions
.eslintignore
.gitignore
+1
-0
1 addition, 0 deletions
.gitignore
app/lib/rules/global_rules.js
+265
-268
265 additions, 268 deletions
app/lib/rules/global_rules.js
app/lib/rules/global_rules.ts
+293
-0
293 additions, 0 deletions
app/lib/rules/global_rules.ts
with
560 additions
and
268 deletions
.eslintignore
+
1
−
0
View file @
33735971
...
...
@@ -12,5 +12,6 @@ app/lib/dal/fileDALs/*.js
app/lib/dal/fileDAL.js
app/service/*.js
app/lib/rules/local_rules.js
app/lib/rules/global_rules.js
test/*.js
test/**/*.js
\ No newline at end of file
This diff is collapsed.
Click to expand it.
.gitignore
+
1
−
0
View file @
33735971
...
...
@@ -48,6 +48,7 @@ app/lib/dal/sqliteDAL/index/*.js*
app/lib/dal/fileDALs/*.js*
app/lib/dal/fileDAL.js*
app/lib/rules/local_rules*.js*
app/lib/rules/global_rules*.js*
app/lib/logger*js*
app/service/*.js*
app/lib/wot.js*
\ No newline at end of file
This diff is collapsed.
Click to expand it.
app/lib/rules/global_rules.js
+
265
−
268
View file @
33735971
This diff is collapsed.
Click to expand it.
app/lib/rules/global_rules.ts
0 → 100644
+
293
−
0
View file @
33735971
"
use strict
"
;
import
{
BlockDTO
}
from
"
../dto/BlockDTO
"
import
{
ConfDTO
}
from
"
../dto/ConfDTO
"
import
{
FileDAL
}
from
"
../dal/fileDAL
"
import
{
DBBlock
}
from
"
../db/DBBlock
"
import
{
DBIdentity
}
from
"
../dal/sqliteDAL/IdentityDAL
"
import
{
TransactionDTO
}
from
"
../dto/TransactionDTO
"
const
co
=
require
(
'
co
'
);
const
_
=
require
(
'
underscore
'
);
const
common
=
require
(
'
duniter-common
'
);
const
indexer
=
require
(
'
../indexer
'
).
Indexer
const
local_rules
=
require
(
'
../rules/local_rules
'
);
const
constants
=
common
.
constants
const
keyring
=
common
.
keyring
const
rawer
=
common
.
rawer
const
Identity
=
common
.
document
.
Identity
const
Transaction
=
common
.
document
.
Transaction
const
unlock
=
common
.
txunlock
export
const
rules
:
any
=
{}
// Empty logger by default
let
logger
=
{
debug
:
(...
args
:
any
[])
=>
{},
warn
:
(...
args
:
any
[])
=>
{}
}
// TODO: all the global rules should be replaced by index rule someday
rules
.
FUNCTIONS
=
{
checkIdentitiesAreWritable
:
async
(
block
:
BlockDTO
,
conf
:
ConfDTO
,
dal
:
FileDAL
)
=>
{
let
current
=
await
dal
.
getCurrentBlockOrNull
();
for
(
const
obj
of
block
.
identities
)
{
let
idty
=
Identity
.
fromInline
(
obj
);
let
found
=
await
dal
.
getWrittenIdtyByUID
(
idty
.
uid
);
if
(
found
)
{
throw
Error
(
'
Identity already used
'
);
}
// Because the window rule does not apply on initial certifications
if
(
current
&&
idty
.
buid
!=
constants
.
SPECIAL_BLOCK
)
{
// From DUP 0.5: we fully check the blockstamp
const
basedBlock
=
await
dal
.
getBlockByBlockstamp
(
idty
.
buid
);
// Check if writable
let
duration
=
current
.
medianTime
-
parseInt
(
basedBlock
.
medianTime
);
if
(
duration
>
conf
.
idtyWindow
)
{
throw
Error
(
'
Identity is too old and cannot be written
'
);
}
}
}
return
true
;
},
checkSourcesAvailability
:
async
(
block
:
BlockDTO
,
conf
:
ConfDTO
,
dal
:
FileDAL
,
alsoCheckPendingTransactions
:
boolean
)
=>
{
const
txs
=
block
.
transactions
const
current
=
await
dal
.
getCurrentBlockOrNull
();
for
(
const
tx
of
txs
)
{
const
inputs
=
tx
.
inputsAsObjects
()
const
outputs
=
tx
.
outputsAsObjects
()
let
unlocks
:
any
=
{};
let
sumOfInputs
=
0
;
let
maxOutputBase
=
current
.
unitbase
;
for
(
const
theUnlock
of
tx
.
unlocks
)
{
let
sp
=
theUnlock
.
split
(
'
:
'
);
let
index
=
parseInt
(
sp
[
0
]);
unlocks
[
index
]
=
sp
[
1
];
}
for
(
let
k
=
0
,
len2
=
inputs
.
length
;
k
<
len2
;
k
++
)
{
let
src
=
inputs
[
k
];
let
dbSrc
=
await
dal
.
getSource
(
src
.
identifier
,
src
.
pos
);
logger
.
debug
(
'
Source %s:%s:%s:%s = %s
'
,
src
.
amount
,
src
.
base
,
src
.
identifier
,
src
.
pos
,
dbSrc
&&
dbSrc
.
consumed
);
if
(
!
dbSrc
&&
alsoCheckPendingTransactions
)
{
// For chained transactions which are checked on sandbox submission, we accept them if there is already
// a previous transaction of the chain already recorded in the pool
dbSrc
=
await
(
async
()
=>
{
let
hypotheticSrc
=
null
;
let
targetTX
=
await
dal
.
getTxByHash
(
src
.
identifier
);
if
(
targetTX
)
{
let
outputStr
=
targetTX
.
outputs
[
src
.
pos
];
if
(
outputStr
)
{
hypotheticSrc
=
Transaction
.
outputStr2Obj
(
outputStr
);
hypotheticSrc
.
consumed
=
false
;
hypotheticSrc
.
time
=
0
;
}
}
return
hypotheticSrc
;
})()
}
if
(
!
dbSrc
||
dbSrc
.
consumed
)
{
logger
.
warn
(
'
Source
'
+
[
src
.
type
,
src
.
identifier
,
src
.
pos
].
join
(
'
:
'
)
+
'
is not available
'
);
throw
constants
.
ERRORS
.
SOURCE_ALREADY_CONSUMED
;
}
sumOfInputs
+=
dbSrc
.
amount
*
Math
.
pow
(
10
,
dbSrc
.
base
);
if
(
block
.
medianTime
-
dbSrc
.
written_time
<
tx
.
locktime
)
{
throw
constants
.
ERRORS
.
LOCKTIME_PREVENT
;
}
let
sigResults
=
local_rules
.
HELPERS
.
getSigResult
(
tx
);
let
unlocksForCondition
=
[];
let
unlocksMetadata
:
any
=
{};
let
unlockValues
=
unlocks
[
k
];
if
(
dbSrc
.
conditions
)
{
if
(
unlockValues
)
{
// Evaluate unlock values
let
sp
=
unlockValues
.
split
(
'
'
);
for
(
const
func
of
sp
)
{
let
param
=
func
.
match
(
/
\((
.+
)\)
/
)[
1
];
if
(
func
.
match
(
/^SIG/
))
{
let
pubkey
=
tx
.
issuers
[
parseInt
(
param
)];
if
(
!
pubkey
)
{
logger
.
warn
(
'
Source
'
+
[
src
.
amount
,
src
.
base
,
src
.
type
,
src
.
identifier
,
src
.
pos
].
join
(
'
:
'
)
+
'
unlock fail (unreferenced signatory)
'
);
throw
constants
.
ERRORS
.
WRONG_UNLOCKER
;
}
unlocksForCondition
.
push
({
pubkey
:
pubkey
,
sigOK
:
sigResults
.
sigs
[
pubkey
]
&&
sigResults
.
sigs
[
pubkey
].
matching
||
false
});
}
else
if
(
func
.
match
(
/^XHX/
))
{
unlocksForCondition
.
push
(
param
);
}
}
}
if
(
dbSrc
.
conditions
.
match
(
/CLTV/
))
{
unlocksMetadata
.
currentTime
=
block
.
medianTime
;
}
if
(
dbSrc
.
conditions
.
match
(
/CSV/
))
{
unlocksMetadata
.
elapsedTime
=
block
.
medianTime
-
dbSrc
.
written_time
;
}
try
{
if
(
!
unlock
(
dbSrc
.
conditions
,
unlocksForCondition
,
unlocksMetadata
))
{
throw
Error
(
'
Locked
'
);
}
}
catch
(
e
)
{
logger
.
warn
(
'
Source
'
+
[
src
.
amount
,
src
.
base
,
src
.
type
,
src
.
identifier
,
src
.
pos
].
join
(
'
:
'
)
+
'
unlock fail
'
);
throw
constants
.
ERRORS
.
WRONG_UNLOCKER
;
}
}
}
let
sumOfOutputs
=
outputs
.
reduce
(
function
(
p
,
output
)
{
if
(
output
.
base
>
maxOutputBase
)
{
throw
constants
.
ERRORS
.
WRONG_OUTPUT_BASE
;
}
return
p
+
output
.
amount
*
Math
.
pow
(
10
,
output
.
base
);
},
0
);
if
(
sumOfInputs
!==
sumOfOutputs
)
{
logger
.
warn
(
'
Inputs/Outputs != 1 (%s/%s)
'
,
sumOfInputs
,
sumOfOutputs
);
throw
constants
.
ERRORS
.
WRONG_AMOUNTS
;
}
}
return
true
;
}
}
rules
.
HELPERS
=
{
// Functions used in an external context too
checkMembershipBlock
:
(
ms
:
any
,
current
:
DBBlock
,
conf
:
ConfDTO
,
dal
:
FileDAL
)
=>
checkMSTarget
(
ms
,
current
?
{
number
:
current
.
number
+
1
}
:
{
number
:
0
},
conf
,
dal
),
checkCertificationIsValid
:
(
cert
:
any
,
current
:
DBBlock
,
findIdtyFunc
:
any
,
conf
:
ConfDTO
,
dal
:
FileDAL
)
=>
checkCertificationIsValid
(
current
?
current
:
{
number
:
0
},
cert
,
findIdtyFunc
,
conf
,
dal
),
checkCertificationIsValidForBlock
:
(
cert
:
any
,
block
:
BlockDTO
,
idty
:
DBIdentity
,
conf
:
ConfDTO
,
dal
:
FileDAL
)
=>
checkCertificationIsValid
(
block
,
cert
,
()
=>
idty
,
conf
,
dal
),
isOver3Hops
:
async
(
member
:
any
,
newLinks
:
any
,
newcomers
:
string
[],
current
:
DBBlock
,
conf
:
ConfDTO
,
dal
:
FileDAL
)
=>
{
if
(
!
current
)
{
return
Promise
.
resolve
(
false
);
}
try
{
return
indexer
.
DUP_HELPERS
.
checkPeopleAreNotOudistanced
([
member
],
newLinks
,
newcomers
,
conf
,
dal
);
}
catch
(
e
)
{
return
true
;
}
},
checkExistsUserID
:
(
uid
:
string
,
dal
:
FileDAL
)
=>
dal
.
getWrittenIdtyByUID
(
uid
),
checkExistsPubkey
:
(
pub
:
string
,
dal
:
FileDAL
)
=>
dal
.
getWrittenIdtyByPubkey
(
pub
),
checkSingleTransaction
:
(
tx
:
TransactionDTO
,
block
:
BlockDTO
,
conf
:
ConfDTO
,
dal
:
FileDAL
,
alsoCheckPendingTransactions
:
boolean
)
=>
rules
.
FUNCTIONS
.
checkSourcesAvailability
({
transactions
:
[
tx
],
medianTime
:
block
.
medianTime
},
conf
,
dal
,
alsoCheckPendingTransactions
),
checkTxBlockStamp
:
async
(
tx
:
TransactionDTO
,
dal
:
FileDAL
)
=>
{
const
number
=
parseInt
(
tx
.
blockstamp
.
split
(
'
-
'
)[
0
])
const
hash
=
tx
.
blockstamp
.
split
(
'
-
'
)[
1
];
const
basedBlock
=
await
dal
.
getBlockByNumberAndHashOrNull
(
number
,
hash
);
if
(
!
basedBlock
)
{
throw
"
Wrong blockstamp for transaction
"
;
}
// Valuates the blockstampTime field
tx
.
blockstampTime
=
basedBlock
.
medianTime
;
const
current
=
await
dal
.
getCurrentBlockOrNull
();
if
(
current
&&
current
.
medianTime
>
basedBlock
.
medianTime
+
constants
.
TX_WINDOW
)
{
throw
"
Transaction has expired
"
;
}
}
}
/*****************************
*
* UTILITY FUNCTIONS
*
*****************************/
async
function
checkMSTarget
(
ms
:
any
,
block
:
any
,
conf
:
ConfDTO
,
dal
:
FileDAL
)
{
if
(
block
.
number
==
0
&&
ms
.
number
!=
0
)
{
throw
Error
(
'
Number must be 0 for root block
\'
s memberships
'
);
}
else
if
(
block
.
number
==
0
&&
ms
.
fpr
!=
'
E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
'
)
{
throw
Error
(
'
Hash must be E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 for root block
\'
s memberships
'
);
}
else
if
(
block
.
number
==
0
)
{
return
null
;
// Valid for root block
}
else
{
let
basedBlock
;
try
{
basedBlock
=
await
dal
.
getBlockByNumberAndHash
(
ms
.
number
,
ms
.
fpr
);
}
catch
(
e
)
{
throw
Error
(
'
Membership based on an unexisting block
'
);
}
let
current
=
await
dal
.
getCurrentBlockOrNull
();
if
(
current
&&
current
.
medianTime
>
basedBlock
.
medianTime
+
conf
.
msValidity
)
{
throw
Error
(
'
Membership has expired
'
);
}
return
basedBlock
;
}
}
async
function
checkCertificationIsValid
(
block
:
any
,
cert
:
any
,
findIdtyFunc
:
any
,
conf
:
ConfDTO
,
dal
:
FileDAL
)
{
if
(
block
.
number
==
0
&&
cert
.
block_number
!=
0
)
{
throw
Error
(
'
Number must be 0 for root block
\'
s certifications
'
);
}
else
{
let
basedBlock
:
any
=
{
hash
:
constants
.
SPECIAL_HASH
};
if
(
block
.
number
!=
0
)
{
try
{
basedBlock
=
await
dal
.
getBlock
(
cert
.
block_number
);
}
catch
(
e
)
{
throw
Error
(
'
Certification based on an unexisting block
'
);
}
try
{
const
issuer
=
await
dal
.
getWrittenIdtyByPubkey
(
cert
.
from
)
if
(
!
issuer
||
!
issuer
.
member
)
{
throw
Error
(
'
Issuer is not a member
'
)
}
}
catch
(
e
)
{
throw
Error
(
'
Certifier must be a member
'
)
}
}
// TODO: weird call, we cannot just do "await findIdtyFunc(...)". There is a bug somewhere.
let
idty
=
await
co
(
function
*
()
{
return
yield
findIdtyFunc
(
block
,
cert
.
to
,
dal
)
})
let
current
=
block
.
number
==
0
?
null
:
await
dal
.
getCurrentBlockOrNull
();
if
(
!
idty
)
{
throw
Error
(
'
Identity does not exist for certified
'
);
}
else
if
(
current
&&
current
.
medianTime
>
basedBlock
.
medianTime
+
conf
.
sigValidity
)
{
throw
Error
(
'
Certification has expired
'
);
}
else
if
(
cert
.
from
==
idty
.
pubkey
)
throw
Error
(
'
Rejected certification: certifying its own self-certification has no meaning
'
);
else
{
const
buid
=
[
cert
.
block_number
,
basedBlock
.
hash
].
join
(
'
-
'
);
if
(
cert
.
block_hash
&&
buid
!=
[
cert
.
block_number
,
cert
.
block_hash
].
join
(
'
-
'
))
throw
Error
(
'
Certification based on an unexisting block buid. from
'
+
cert
.
from
.
substring
(
0
,
8
)
+
'
to
'
+
idty
.
pubkey
.
substring
(
0
,
8
));
idty
.
currency
=
conf
.
currency
;
const
raw
=
rawer
.
getOfficialCertification
(
_
.
extend
(
idty
,
{
idty_issuer
:
idty
.
pubkey
,
idty_uid
:
idty
.
uid
,
idty_buid
:
idty
.
buid
,
idty_sig
:
idty
.
sig
,
issuer
:
cert
.
from
,
buid
:
buid
,
sig
:
''
}));
const
verified
=
keyring
.
verify
(
raw
,
cert
.
sig
,
cert
.
from
);
if
(
!
verified
)
{
throw
constants
.
ERRORS
.
WRONG_SIGNATURE_FOR_CERT
}
return
true
;
}
}
}
export
function
setLogger
(
newLogger
:
any
)
{
logger
=
newLogger
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment