func (t *LogTreap) Slice(start, end int32, c comp.C) *seqhash.Hash { if t == nil { return new(seqhash.Hash) } c.Use(t) if start <= 0 && end >= t.Num { return t.SeqHash(c) } leftCount := t.Left.Count(c) h := new(seqhash.Hash) if start < leftCount { h = seqhash.Merge(h, t.Left.Slice(start, end, c), c) } if start <= leftCount && end >= leftCount+1 { h = seqhash.Merge(h, seqhash.New(t.Value), c) } if end > leftCount+1 { h = seqhash.Merge(h, t.Right.Slice(start-leftCount-1, end-leftCount-1, c), c) } return h }
func (h *Hash) Finish(c comp.C) Hashable { c.Use(h) if h.Empty() { return nil } left := make([]Hashable, 0) right := make([]Hashable, 0) for i := int8(0); i < h.Height; i++ { left = append(left, h.LeftFringes[i]...) right = append(h.RightFringes[i], right...) left = doRound(left, false, false, c).center right = doRound(right, false, false, c).center } elems := append(append(left, h.Top...), right...) for len(elems) > 1 { elems = doRound(elems, false, false, c).center } return elems[0] }
func ProcessTransactionImpl(transaction *Transaction, balances bitrie.Bitrie, c comp.C) bitrie.Bitrie { c.Use(transaction, balances) for _, input := range transaction.MsgTx.TxIn { if (input.PreviousOutpoint.Hash == btcwire.ShaHash{}) { continue } balances = ProcessOutpoint(input.PreviousOutpoint, balances, c) } loc := bitrie.MakeBits(ads.Hash(transaction)) x, found := balances.Get(loc, c) var oi *OutpointInfo if found { oi = x.(*OutpointInfo) } else { oi = &OutpointInfo{} } c.Use(oi) oi = oi.Add(len(transaction.MsgTx.TxOut)) return balances.Set(loc, oi, c) }
func (l *BitrieLeaf) Set(b Bits, value ads.ADS, c comp.C) Bitrie { c.Use(l) s := SplitPoint(l.Bits, b) if s == b.Length { return &BitrieLeaf{ Bits: b, Value: value, } } left := &BitrieLeaf{ Bits: b.Cut(s+1, b.Length), Value: value, } right := &BitrieLeaf{ Bits: l.Bits.Cut(s+1, l.Bits.Length), Value: l.Value, } if b.Get(s) != 0 { left, right = right, left } return &BitrieNode{ Bits: b.Cut(0, s), Left: left, Right: right, } }
func (l *LogEntry) Index(idx int32, c comp.C) *LogEntry { c.Use(l) if idx != 0 { panic(idx) } return l }
func CombineTree(left, right LogTree, c comp.C) *LogTreeNode { c.Use(left, right) return &LogTreeNode{ Num: left.Count() + right.Count(), Left: left, Right: right, } }
func ProcessBlock(block *core.Block, txns, regs bitrie.Bitrie, c comp.C) (bitrie.Bitrie, bitrie.Bitrie) { c.Use(block) for _, txn := range block.Transactions { txns, regs = ProcessTxn(txn.(*core.Transaction), txns, regs, c) } return txns, regs }
func ProcessTxnImpl(txn *core.Transaction, txns bitrie.Bitrie, c comp.C) bitrie.Bitrie { c.Use(txn) for _, output := range txn.MsgTx.TxOut { txns = ProcessOutput(txn, output, txns, c) } return txns }
func (l *LogTreeNode) Index(idx int32, c comp.C) *LogEntry { c.Use(l) c.Use(l.Left) if idx < l.Left.Count() { return l.Left.Index(idx, c) } return l.Right.Index(idx-l.Left.Count(), c) }
func (l *BitrieLeaf) Delete(b Bits, c comp.C) Bitrie { c.Use(l) if SplitPoint(l.Bits, b) < l.Bits.Length { return l } return Nil }
func (t *LogTreap) Count(c comp.C) int32 { if t == nil { return 0 } c.Use(t) return t.Num }
func ProcessBlock(block *Block, balances bitrie.Bitrie, c comp.C) bitrie.Bitrie { c.Use(block) for _, transaction := range block.Transactions { balances = ProcessTransaction(transaction.(*Transaction), balances, c) } return balances }
func CalculateRegsImpl(block *core.Block, c comp.C) (bitrie.Bitrie, bitrie.Bitrie) { if block == nil { return bitrie.Nil, bitrie.Nil } c.Use(block) txns, regs := CalculateRegs(block.Previous, c) txns, regs = ProcessBlock(block, txns, regs, c) return txns, regs }
func (l *BitrieLeaf) Get(b Bits, c comp.C) (ads.ADS, bool) { c.Use(l) s := SplitPoint(l.Bits, b) if s == b.Length { return l.Value, true } return nil, false }
func ProcessTxnImpl(txn *core.Transaction, txns, regs bitrie.Bitrie, c comp.C) (bitrie.Bitrie, bitrie.Bitrie) { c.Use(txn) txns = txns.Set(bitrie.MakeBits(txn.ComputeHash()), txn, c) if len(txn.MsgTx.TxOut) != 1 { return txns, regs } script := txn.MsgTx.TxOut[0].PkScript if len(script) < 1 || script[0] != btcscript.OP_RETURN { return txns, regs } data := script[1:] if len(data) != 40 { return txns, regs } if !bytes.Equal(data[0:8], tag) { return txns, regs } loc := bitrie.MakeBits(sha.Sum(data[8:40])) ads, found := regs.Get(loc, c) claim := ads.(*Claim) // two types of txns: register and transfer if len(txn.MsgTx.TxIn) == 1 { if found { return txns, regs } key := GetKey(txns, txn.MsgTx.TxIn[0].PreviousOutpoint, c) regs = regs.Set(loc, &Claim{Key: key}, c) } if len(txn.MsgTx.TxIn) == 2 { if !found { return txns, regs } from := GetKey(txns, txn.MsgTx.TxIn[0].PreviousOutpoint, c) if !bytes.Equal(from, claim.Key) { return txns, regs } to := GetKey(txns, txn.MsgTx.TxIn[1].PreviousOutpoint, c) regs = regs.Set(loc, &Claim{Key: to}, c) } return txns, regs }
func CalculateTxnsImpl(block *core.Block, c comp.C) bitrie.Bitrie { if block == nil { return bitrie.Nil } c.Use(block) txns := CalculateTxns(block.Previous, c) txns = ProcessBlock(block, txns, c) return txns }
func CalculateBalancesImpl(block *Block, c comp.C) bitrie.Bitrie { if block == nil { return bitrie.Nil } c.Use(block) balances := CalculateBalances(block.Previous, c) balances = ProcessBlock(block, balances, c) return balances }
// TODO: make sure seqhash is only encoded when merged != nil.... func (t *LogTreap) SeqHash(c comp.C) *seqhash.Hash { if t == nil { return new(seqhash.Hash) } c.Use(t) if t.Merged == nil { t.Merged = t.computeSeqHash(c) } return t.Merged }
func BitrieSize(balances bitrie.Bitrie, c comp.C) int { c.Use(balances) if _, ok := balances.(*bitrie.BitrieLeaf); ok { return 1 } if node, ok := balances.(*bitrie.BitrieNode); ok { return BitrieSize(node.Left, c) + BitrieSize(node.Right, c) } log.Panic("wut!") return 0 }
func (n *BitrieNode) Get(b Bits, c comp.C) (ads.ADS, bool) { c.Use(n) if SplitPoint(n.Bits, b) < n.Bits.Length { return nil, false } tail := b.Cut(n.Bits.Length+1, b.Length) if b.Get(n.Bits.Length) == 0 { return n.Left.Get(tail, c) } else { return n.Right.Get(tail, c) } }
func CombineTreap(left, right *LogTreap, c comp.C) *LogTreap { if left == nil { return right } else if right == nil { return left } c.Use(left, right) if left.Priority > right.Priority { return left.UpdateRight(CombineTreap(left.Right, right, c), c) } else { return right.UpdateLeft(CombineTreap(left, right.Left, c), c) } }
func (n *BitrieNode) Set(b Bits, value ads.ADS, c comp.C) Bitrie { c.Use(n) s := SplitPoint(n.Bits, b) if s < n.Bits.Length { var left, right Bitrie left = &BitrieLeaf{ Bits: b.Cut(s+1, b.Length), Value: value, } right = &BitrieNode{ Bits: n.Bits.Cut(s+1, n.Bits.Length), Left: n.Left, Right: n.Right, } if b.Get(s) != 0 { left, right = right, left } return &BitrieNode{ Bits: n.Bits.Cut(0, s), Left: left, Right: right, } } else { tail := b.Cut(n.Bits.Length+1, b.Length) if b.Get(n.Bits.Length) == 0 { newLeft := n.Left.Set(tail, value, c) return &BitrieNode{ Bits: n.Bits, Left: newLeft, Right: n.Right, } } else { newRight := n.Right.Set(tail, value, c) return &BitrieNode{ Bits: n.Bits, Left: n.Left, Right: newRight, } } } }
func RandomKey(prefix bitrie.Bits, balances bitrie.Bitrie, c comp.C) bitrie.Bits { if leaf, ok := balances.(*bitrie.BitrieLeaf); ok { c.Use(leaf) return prefix.Cat(leaf.Bits) } if node, ok := balances.(*bitrie.BitrieNode); ok { c.Use(node) if rand.Intn(2) == 0 { return RandomKey(prefix.Cat(node.Bits).Append(0), node.Left, c) } else { return RandomKey(prefix.Cat(node.Bits).Append(1), node.Right, c) } } panic(balances) }
func ProcessOutpointImpl(outpoint btcwire.OutPoint, balances bitrie.Bitrie, c comp.C) bitrie.Bitrie { loc := bitrie.MakeBits(sha.Hash(outpoint.Hash)) x, found := balances.Get(loc, c) var oi *OutpointInfo if found { oi = x.(*OutpointInfo) } else { oi = &OutpointInfo{} } c.Use(oi) oi = oi.Spend(int(outpoint.Index)) if oi.Empty() { return balances.Delete(loc, c) } else { return balances.Set(loc, oi, c) } }
func Resolve(lt LogTree, c comp.C) (*LogEntry, error) { c.Use(lt) pos := lt.Count() - 1 expected := make([]*LogEntry, 0) for { if pos == -1 { return nil, nil } entry := lt.Index(pos, c) expected = append(expected, entry) c.Use(entry) if entry.Type == FunctionEntry { break } else { pos -= entry.Length entryEntry := lt.Index(pos, c) expected = append(expected, entryEntry) pos-- } } n := len(expected) for i := 0; i < n/2; i++ { expected[i], expected[n-1-i] = expected[n-1-i], expected[i] } resolveC := ResolveC{ Outer: c, Expected: expected, } return resolveC.Resolve() }
func Dump(prefix bitrie.Bits, balances bitrie.Bitrie, c comp.C) { if leaf, ok := balances.(*bitrie.BitrieLeaf); ok { c.Use(leaf) c.Use(leaf.Value) fmt.Printf("%v: %v\n", hex.EncodeToString(prefix.Cat(leaf.Bits).Bits), leaf.Value.(*OutpointInfo).Count) } if node, ok := balances.(*bitrie.BitrieNode); ok { c.Use(node) Dump(prefix.Cat(node.Bits).Append(0), node.Left, c) Dump(prefix.Cat(node.Bits).Append(1), node.Right, c) } }
func (n *BitrieNode) Delete(b Bits, c comp.C) Bitrie { c.Use(n) if SplitPoint(n.Bits, b) < n.Bits.Length { return n } tail := b.Cut(n.Bits.Length+1, b.Length) if b.Get(n.Bits.Length) == 0 { newLeft := n.Left.Delete(tail, c) if _, isNil := newLeft.(*BitrieNil); isNil { c.Use(n.Right) return n.Right.prepend(n.Bits.Append(1)) } else { return &BitrieNode{ Bits: n.Bits, Left: newLeft, Right: n.Right, } } } else { newRight := n.Right.Delete(tail, c) if _, isNil := newRight.(*BitrieNil); isNil { c.Use(n.Left) return n.Left.prepend(n.Bits.Append(0)) } else { return &BitrieNode{ Bits: n.Bits, Left: n.Left, Right: newRight, } } } }
func Merge(left, right *Hash, c comp.C) *Hash { if left != nil { c.Use(left) } if right != nil { c.Use(right) } if left.Empty() { return right } if right.Empty() { return left } Calls++ merged := Hash{} elems := make([]Hashable, 0) for { if merged.Height < left.Height { elems = append(left.RightFringes[merged.Height], elems...) } else if merged.Height == left.Height { elems = append(left.Top, elems...) } if merged.Height < right.Height { elems = append(elems, right.LeftFringes[merged.Height]...) } else if merged.Height == right.Height { elems = append(elems, right.Top...) } if merged.Height >= left.Height && merged.Height >= right.Height && len(elems) == 0 { break } round := doRound(elems, merged.Height >= left.Height, merged.Height >= right.Height, c) elems = round.center if merged.Height < left.Height { merged.LeftFringes = append(merged.LeftFringes, left.LeftFringes[merged.Height]) } else { merged.LeftFringes = append(merged.LeftFringes, round.leftFringe) } if merged.Height < right.Height { merged.RightFringes = append(merged.RightFringes, right.RightFringes[merged.Height]) } else { merged.RightFringes = append(merged.RightFringes, round.rightFringe) } merged.Height++ } merged.Height-- merged.Top = append(merged.LeftFringes[merged.Height], merged.RightFringes[merged.Height]...) merged.LeftFringes = merged.LeftFringes[:merged.Height] merged.RightFringes = merged.RightFringes[:merged.Height] return &merged }