Skip to content

Instantly share code, notes, and snippets.

Michael Graczyk mgraczyk

Block or report user

Report or block mgraczyk

Hide content and notifications from this user.

Learn more about blocking users

Contact Support about this user’s behavior.

Learn more about reporting abuse

Report abuse
View GitHub Profile
View perlin10.go
func (n *Node) IsAccepted(tx *Transaction) bool {
mutex.RLock()
defer mutex.RUnlock()
committed := false
for _, parent := range tx.Body.GetParents() {
parent := n.Transactions[parent]
committed = committed && n.IsAccepted(parent)
}
set := n.Conflicts[tx.Body.Utxo]
// [OT] safe early commitment.
View perlin9.go
// ... update the preference for ancestors
// [OT] This only loops over parents, not ancestors
for _, parentId := range tx.Body.Parents {
mutex.RLock()
parent := n.Transactions[parentId]
conflicts := n.Conflicts[parent.Body.Utxo]
mutex.RUnlock()
parentScore, presentScore := n.Confidence(parent), n.Confidence(conflicts.Preferred)
if parentScore > presentScore {
conflicts.Preferred = parent
View perlin8.go
func QueryEvents(n *Node, rpc RPC) {
// [OT] Line 2 with modified condition
for id, tx := range n.Unqueried() {
// [OT] Check that the transactions parents are known
// In a real implementation, undigestible txns
// would eventually need to be pruned.
if !n.IsDigestable(tx) {
continue
}
// [OT] Lines 4-5
View perlin7.go
func (n *Node) IsStronglyPreferred(tx *Transaction) bool {
mutex.RLock()
defer mutex.RUnlock()
stronglyPreferred := true
parents := // ... make map of parent ids
for len(parents) != 0 {
for parentId := range parents {
// [OT] stronglyPreferred could be memoized here for efficiency
// This is a downside of using protocol buffers for state.
// Additional in-memory state can't be stored naturally because
View perlin6.go
func (n *Node) OnReceiveTx(tx *Transaction) bool {
// ... Verify tx
// [OT] Take a global read lock.
mutex.Lock()
defer mutex.Unlock()
// [OT] Line 9
if _, received := n.Transactions[tx.Id]; !received {
// [OT] Line 10
if set, exists := n.Conflicts[tx.Body.Utxo]; exists {
set.Transactions[tx.Id] = tx // [OT] Line 13
View perlin5.go
case *messages.QueryRequest:
response := &messages.QueryResponse{}
if msg.Transaction != nil && msg.Transaction.Verify() {
stronglyPreferred := state.node.OnQueryTx(msg.Transaction)
response.Transaction = msg.Transaction.Id
response.StronglyPreferred = stronglyPreferred
ctx.Respond(response)
}
// [OT] Always respond with empty? Does this overwrite?
ctx.Respond(response)
View perlin4.go
// Searches for suitable parent transactions for a new transaction.
func (n *Node) SelectParents() []string {
// [OT] The lock could be held for less time with BFS
mutex.RLock()
defer mutex.RUnlock()
var eligibleParents []*Transaction
// [OT] Search every historical transaction.
for _, tx := range n.Transactions {
if n.IsStronglyPreferred(tx) {
// [OT] Figure 19, line 2
View perlin3.go
// [OT] This case corresponds to onGenerateTx in the paper.
case *messages.ApiReceiveTransaction:
// [OT] small race, should be `utxo := atomic.Add...() - 1`
// already being fixed by Perlin
utxo := atomic.LoadUint64(&messages.LastUTXO)
atomic.AddUint64(&messages.LastUTXO, 1)
body := messages.CreateTx(utxo, store.GetKeys().PublicKeyHex(), state.node.SelectParents(), msg.Data)
state.node.OnReceiveTx(body.Sign(store.GetKeys()))
View perlin2.go
func (state *NodeActor) Receive(ctx actor.Context) {
switch msg := ctx.Message().(type) {
// ... Other cases for starting, stopping
case *messages.QueryRequest:
// ...
case *messages.ApiReceiveTransaction:
// ...
}
View perlin1.go
message Node {
map<string, Transaction> queried = 1;
map<string, Transaction> transactions = 2;
map<uint64, ConflictSet> conflicts = 3;
map<string, uint64> chits = 4;
}
You can’t perform that action at this time.