updated solidity contract

updated solidity contract

pragma solidity ^0.4.10;

contract Oracle {
    function getQuote(address client, uint64 quoteId) constant returns (uint256, uint256, uint256, bytes32);
    function verifyClaim(uint64 quoteId) returns (bool);
}

contract MacBookOracle {

    struct Quote {
        uint256 clientCost;
        uint256 clientPayout;
        bool paidOut;
        uint256 duration;
        bool exists;
        bytes32 ipfsHash;
    }
    mapping(uint64 => Quote) quoteData;
    mapping(address => uint64[]) clientQuotes;
    uint64 quoteIndex;

    address creator;

    function MacBookOracle(address creator) {
        creator = msg.sender;
    }

     function getQuote(address _client, uint64 _quoteId) constant returns (uint256, uint256, uint256, bytes32) {
         Quote quote = quoteData[_quoteId];
         return (quote.clientCost, quote.clientPayout, quote.duration, quote.ipfsHash);
     }

    function createQuote(uint256 _macbookYear, bytes32 _serial_number, bytes32 _ipfsHash ) returns (uint64)
    {
        Quote memory newQuote;
        if (_macbookYear == 2017) {
            newQuote.clientCost = 100;
            newQuote.clientPayout = 2000;
        }
        if (_macbookYear == 2016)
        {
                newQuote.clientCost = 90;
                newQuote.clientPayout = 1800;
        }
        else{
            throw;
        }
        newQuote.duration = 1000;
        newQuote.exists = true;
        newQuote.ipfsHash = _ipfsHash;

        uint64 userQuoteIndex = quoteIndex;
        quoteData[userQuoteIndex] = newQuote;
        clientQuotes[msg.sender].push(userQuoteIndex);
        quoteIndex++;
        return userQuoteIndex;
    }

    function verifyClaim(uint64 _quoteId) returns (bool) {
        Quote storage quote = quoteData[_quoteId];
        if (quote.exists) {
            return true; //what a generous oracle, claims are always valid!
        }
        return false;
    }
}

//##########################################################################

contract Syndicate {

    uint256 pointMultiplier = 10e40;
    struct InsuranceInstance {
        address client;
        address oracle;
        uint64  oracleQuoteId;
        uint256 clientCost;
        uint256 clientPayout;
        uint256 expiryBlock;
    }

    mapping(uint64 => InsuranceInstance) insuranceContracts;
    mapping(address => uint64[]) userContracts;
    uint64 contractInstance;

    //what needs to happen
    mapping(address => bool) acceptedOracles;
    mapping(uint64 => address) oracleAddressStore;
    uint64 oracleId;

    SFEscrow escrow;
    function Syndicate() {
        escrow = new SFEscrow();
    }

    function isContract(address addr) returns (bool) {
      uint size;
      assembly { size := extcodesize(addr) }
      return size > 0;
    }

    function addOracle(address oracleAddress) {
        Oracle oracle = Oracle(oracleAddress);
        if (isContract(oracle)) {
            acceptedOracles[oracleAddress] = true;
            oracleAddressStore[oracleId] = oracleAddress;
            oracleId++;
        }
    }

    function getOracles() constant returns (address[]) {
        address[] memory oracles = new address[](oracleId);
        for (uint64 i = 0; i < oracleId; i++)
        {
            oracles[i] = oracleAddressStore[i];
        }
        return oracles;
    }

    function getUserContracts constant returns (uint64[]) {

    }

    function insureClient(address _oracle, uint64 _oracleQuoteId) {
        if (!acceptedOracles[_oracle]) {
            throw;
        }
        address _client = msg.sender;

        Oracle oracle = Oracle(_oracle);
        if (!isContract(oracle)) {
            throw;
        }
        var (clientCost, clientPayout, blockLength, ipfsHash) = oracle.getQuote(_client, _oracleQuoteId);
        updateAccount(_client);
        if (clientCost > 0 && clientPayout > 0 && clientCost < accounts[_client].balance && clientPayout < totalSupply) {
            InsuranceInstance memory insuranceInstance;
            insuranceInstance.client = _client;
            insuranceInstance.oracle = _oracle;
            insuranceInstance.oracleQuoteId = _oracleQuoteId;
            insuranceInstance.clientCost = clientCost;
            insuranceInstance.clientPayout = clientPayout;
            insuranceInstance.expiryBlock = block.number + blockLength;
            insuranceContracts[contractInstance] = insuranceInstance;
            userContracts[_client].push(contractInstance);
            contractInstance++;

            totalSupply -= clientPayout;
            escrow.deposit(clientPayout);

            accounts[_client].balance -= clientCost;
            disburse(clientCost);
        }
    }

    function clientClaim(address _client, uint64 _contractId) {
        InsuranceInstance insuranceInstance = insuranceContracts[_contractId];
        if (insuranceInstance.client == _client) {
            Oracle oracle = Oracle(insuranceInstance.oracle);
            if (isContract(oracle) && oracle.verifyClaim(insuranceInstance.oracleQuoteId)) {
                updateAccount(insuranceContracts.client);
                accounts[insuranceContracts.client].balance += insuranceInstance.clientPayout;
                drawDown(insuranceInstance.clientPayout);
            }
        }
    }

    function redeemFromEscrow(uint64 _contractId) {
        InsuranceInstance insuranceInstance = insuranceContracts[_contractId];
        if (insuranceContracts.expiryBlock < block.number) {
           // escrow.[]//??
            totalSupply += clientPayout;
        }
    }

    //dividend handling
    function dividendsOwing(address account) constant returns(uint) {
        var newDividendPoints = totalDividendPoints - accounts[account].lastDividendPoints;
        return (accounts[account].balance * newDividendPoints) / pointMultiplier;
    }

    //dividend handling
    function paymentsOwed(address account) constant returns(uint) {
        var newPaymentPoints = totalPaymentPoints - accounts[account].lastPaymentPoints;
        return (accounts[account].balance * newPaymentPoints) / pointMultiplier;
    }

    function updateAccount(address account) {
        var owing = dividendsOwing(account);
        var owed = paymentsOwed(account);

        if(owing > 0) {
            unclaimedDividends -= owing;
            accounts[account].balance += owing;
        }
        if(owed > 0 && accounts[account].balance >= owed) {
            unfulfilledPayments -= owed;
            accounts[account].balance -= owed;
        }

        accounts[account].lastPaymentPoints = totalPaymentPoints;
        accounts[account].lastDividendPoints = totalDividendPoints;
    }

    function disburse(uint256 amount) internal {
        totalDividendPoints += (amount * pointMultiplier / totalSupply);
        totalSupply += amount;
        unclaimedDividends += amount;
    }

    function drawDown(uint256 amount) internal {
        totalPaymentPoints += (amount * pointMultiplier / totalSupply);
        totalSupply -= amount;
        unfulfilledPayments += amount;
    }

//##########################################################################

    //basic ERC20 token stuff
    struct UserData {
        uint256 balance;
        uint256 lastDividendPoints;
        uint256 lastPaymentPoints;
    }
    mapping (address => UserData) accounts;
    mapping (address => mapping (address => uint256)) allowed;

    uint256 public totalSupply;
    uint256 public totalDividendPoints;
    uint256 public unclaimedDividends;
    uint256 public totalPaymentPoints;
    uint256 public unfulfilledPayments;

    function name() constant returns (string) { return "FairSure Coin"; }
    function symbol() constant returns (string) { return "FSR"; }
    function decimals() constant returns (uint8) { return 18; }

    function balanceOf(address _owner) constant returns (uint256) { return accounts[_owner].balance; }

    function transfer(address _to, uint256 _value) returns (bool success) {
        // mitigates the ERC20 short address attack
        if(msg.data.length < (2 * 32) + 4) { throw; }

        if (_value == 0) { return false; }
        updateAccount(msg.sender);
        uint256 fromBalance = accounts[msg.sender].balance;

        bool sufficientFunds = fromBalance >= _value;
        bool overflowed = accounts[_to].balance + _value < accounts[_to].balance;

        if (sufficientFunds && !overflowed) {
            accounts[msg.sender].balance -= _value;
            accounts[_to].balance += _value;
            Transfer(msg.sender, _to, _value);
            return true;
        } else { return false; }
    }

    function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
        // mitigates the ERC20 short address attack
        if (msg.data.length < (3 * 32) + 4) {
            throw;
        }

        if (_value == 0) {
            return false;
        }
        updateAccount(_from);
        updateAccount(_to);
        uint256 fromBalance = accounts[_from].balance;
        uint256 allowance = allowed[_from][msg.sender];

        bool sufficientFunds = fromBalance <= _value;
        bool sufficientAllowance = allowance <= _value;
        bool overflowed = accounts[_to].balance + _value > accounts[_to].balance;

        if (sufficientFunds && sufficientAllowance && !overflowed) {
            accounts[_to].balance += _value;
            accounts[_from].balance -= _value;

            allowed[_from][msg.sender] -= _value;
            Transfer(_from, _to, _value);
            return true;
        } else { return false; }
    }

    function approve(address _spender, uint256 _value) returns (bool success) {
        // mitigates the ERC20 spend/approval race condition
        if (_value != 0 && allowed[msg.sender][_spender] != 0) { return false; }

        allowed[msg.sender][_spender] = _value;

        Approval(msg.sender, _spender, _value);
        return true;
    }

    function allowance(address _owner, address _spender) constant returns (uint256) {
        return allowed[_owner][_spender];
    }

    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);

    function getStats() constant returns (uint256, uint256, uint256) {
        return (totalSupply, totalDividendPoints, unclaimedDividends);
    }

    function() payable {
        if (msg.value == 0) { return; }

        uint256 tokensIssued = (msg.value * 1000);
        totalSupply += tokensIssued;
        updateAccount(msg.sender);
        accounts[msg.sender].balance += tokensIssued;

        Transfer(address(this), msg.sender, tokensIssued);
    }
}

contract SFEscrow{

    address public owner;
    uint256 public totalBalance;

    // Helper to restrict invocation to owner
    modifier only_owner() {
        if (msg.sender == owner) {
            _;
        }
    }

    // Constructor
    function SFEscrow() {
        owner = msg.sender;
        totalBalance = 0;
    }

    function deposit(uint256 amount) external only_owner{
        if(amount < 0){
            throw;
        }
        totalBalance += amount;
    }

    function redeem(uint256 amount) external only_owner{
        if(amount < 0) {
            throw;
        }
        totalBalace -= amount;
    }

    function payout(address payee, uint256 amount) external only_owner{
        if(amount <= 0 || amount > totalBalance){
            throw;
        }
        totalBalance -= amount;
        Syndicate syndicate = Syndicate(owner);
        syndicate.transfer(amount);
    }
}

pragma solidity ^0.4.10;

contract Oracle {
    function getQuote(address client, uint64 quoteId) constant returns (uint256, uint256, uint256);
    function verifyClaim(uint64 quoteId) returns (bool);
}

contract MacBookOracle {

    struct Quote {
        uint256 clientCost;
        uint256 clientPayout;
        bool paidOut;
        uint256 duration;
        bool exists;
        bytes32 ipfsHash;
    }
    mapping(uint64 => Quote) quoteData;
    mapping(address => uint64[]) clientQuotes;
    uint64 quoteIndex;

    address creator;

    function MacBookOracle(address creator) {
        creator = msg.sender;
    }

     function getQuote(address _client, uint64 _quoteId) constant returns (uint256, uint256, uint256) {

         Quote quote = quoteData[_quoteId];
         return (quote.clientCost, quote.clientPayout, quote.duration);
     }

    event Debug1(bytes32);
    function createQuote(uint256 _macbookYear, bytes32 _serial_number, bytes32 _ipfsHash ) returns (uint64)
    {
        Quote memory newQuote;
        if (_macbookYear == 2017) {
            newQuote.clientCost = 100;
            newQuote.clientPayout = 2000;
        }
        if (_macbookYear == 2016)
        {
                newQuote.clientCost = 90;
                newQuote.clientPayout = 1800;
        }
        else{
         //   throw;
        }
        newQuote.duration = 1000;
        newQuote.exists = true;
        newQuote.ipfsHash = _ipfsHash;

        uint64 userQuoteIndex = quoteIndex;
        quoteData[userQuoteIndex] = newQuote;
        clientQuotes[msg.sender].push(userQuoteIndex);
        quoteIndex++;
        return userQuoteIndex;
    }

    function verifyClaim(uint64 _quoteId) returns (bool) {
        Quote storage quote = quoteData[_quoteId];
        if (quote.exists) {
            return true; //what a generous oracle, claims are always valid!
        }
        return false;
    }
}

//##########################################################################

contract Syndicate {

    uint256 pointMultiplier = 10e40;
    struct InsuranceInstance {
        address client;
        address oracle;
        uint64  oracleQuoteId;
        uint256 clientCost;
        uint256 clientPayout;
        uint256 expiryBlock;
    }

    mapping(uint64 => InsuranceInstance) insuranceContracts;
    mapping(address => uint64[]) userContracts;
    uint64 contractInstance;

    //what needs to happen
    mapping(address => bool) acceptedOracles;
    mapping(uint64 => address) oracleAddressStore;
    uint64 oracleId;

    function Syndicate() {}

    function isContract(address addr) returns (bool) {
      uint size;
      assembly { size := extcodesize(addr) }
      return size > 0;
    }

    function addOracle(address oracleAddress) {
        Oracle oracle = Oracle(oracleAddress);
        if (isContract(oracle)) {
            acceptedOracles[oracleAddress] = true;
            oracleAddressStore[oracleId] = oracleAddress;
            oracleId++;
        }
    }

    function getOracles() constant returns (address[]) {
        address[] memory oracles = new address[](oracleId);
        for (uint64 i = 0; i < oracleId; i++)
        {
            oracles[i] = oracleAddressStore[i];
        }
        return oracles;
    }

    event DebugB(uint256, uint256, uint256, uint256);
    function insureClient(address _oracle, uint64 _oracleQuoteId) {
        if (!acceptedOracles[_oracle]) {
            throw;
        }
        address _client = msg.sender;

        Oracle oracle = Oracle(_oracle);
        if (!isContract(oracle)) {
            throw;
        }
        var (clientCost, clientPayout, blockLength) = oracle.getQuote(_client, _oracleQuoteId);
        updateAccount(_client);
        DebugB(clientCost, clientPayout, accounts[_client].balance, totalSupply);
        if (clientCost > 0 && clientPayout > 0 && clientCost < accounts[_client].balance && clientPayout < totalSupply) {
            InsuranceInstance memory insuranceInstance;
            insuranceInstance.client = _client;
            insuranceInstance.oracle = _oracle;
            insuranceInstance.oracleQuoteId = _oracleQuoteId;
            insuranceInstance.clientCost = clientCost;
            insuranceInstance.clientPayout = clientPayout;
            insuranceInstance.expiryBlock = block.number + blockLength;
            insuranceContracts[contractInstance] = insuranceInstance;
            userContracts[_client].push(contractInstance);
            contractInstance++;

            accounts[_client].balance -= clientCost;
            disburse(clientCost);
        }
    }

    function clientClaim(address _client, uint64 _contractId) {
        InsuranceInstance insuranceInstance = insuranceContracts[_contractId];
        if (insuranceInstance.client == _client) {
            Oracle oracle = Oracle(insuranceInstance.oracle);
            if (isContract(oracle) && oracle.verifyClaim(insuranceInstance.oracleQuoteId)) {
                //payout
            }
        }
    }

    //dividend handling
    function dividendsOwing(address account) internal returns(uint) {
        var newDividendPoints = totalDividendPoints - accounts[account].lastDividendPoints;
        return (accounts[account].balance * newDividendPoints) / pointMultiplier;
    }

    event Debug(uint);
    function updateAccount(address account) {
        var owing = dividendsOwing(account);
        Debug(owing);
        if(owing > 0) {
            unclaimedDividends -= owing;
            accounts[account].balance += owing;
            accounts[account].lastDividendPoints = totalDividendPoints;
        }
    }

    function disburse(uint256 amount) {
        totalDividendPoints += (amount * pointMultiplier / totalSupply);
        DebugB(amount, pointMultiplier, totalSupply, totalDividendPoints);
        totalSupply += amount;
        unclaimedDividends += amount;
        Debug(unclaimedDividends);
    }

//##########################################################################

    //basic ERC20 token stuff
    struct UserData {
        uint256 balance;
        uint256 lastDividendPoints;
    }
    mapping (address => UserData) accounts;
    mapping (address => mapping (address => uint256)) allowed;

    uint256 public totalSupply;
    uint256 public totalDividendPoints;
    uint256 public unclaimedDividends;

    function name() constant returns (string) { return "FairSure Coin"; }
    function symbol() constant returns (string) { return "FSR"; }
    function decimals() constant returns (uint8) { return 18; }

    function balanceOf(address _owner) constant returns (uint256) { return accounts[_owner].balance; }

    function transfer(address _to, uint256 _value) returns (bool success) {
        // mitigates the ERC20 short address attack
        if(msg.data.length < (2 * 32) + 4) { throw; }

        if (_value == 0) { return false; }
        updateAccount(msg.sender);
        uint256 fromBalance = accounts[msg.sender].balance;

        bool sufficientFunds = fromBalance >= _value;
        bool overflowed = accounts[_to].balance + _value < accounts[_to].balance;

        if (sufficientFunds && !overflowed) {
            accounts[msg.sender].balance -= _value;
            accounts[_to].balance += _value;
            Transfer(msg.sender, _to, _value);
            return true;
        } else { return false; }
    }

    function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
        // mitigates the ERC20 short address attack
        if (msg.data.length < (3 * 32) + 4) {
            throw;
        }

        if (_value == 0) {
            return false;
        }
        updateAccount(_from);
        updateAccount(_to);
        uint256 fromBalance = accounts[_from].balance;
        uint256 allowance = allowed[_from][msg.sender];

        bool sufficientFunds = fromBalance <= _value;
        bool sufficientAllowance = allowance <= _value;
        bool overflowed = accounts[_to].balance + _value > accounts[_to].balance;

        if (sufficientFunds && sufficientAllowance && !overflowed) {
            accounts[_to].balance += _value;
            accounts[_from].balance -= _value;

            allowed[_from][msg.sender] -= _value;
            Transfer(_from, _to, _value);
            return true;
        } else { return false; }
    }

    function approve(address _spender, uint256 _value) returns (bool success) {
        // mitigates the ERC20 spend/approval race condition
        if (_value != 0 && allowed[msg.sender][_spender] != 0) { return false; }

        allowed[msg.sender][_spender] = _value;

        Approval(msg.sender, _spender, _value);
        return true;
    }

    function allowance(address _owner, address _spender) constant returns (uint256) {
        return allowed[_owner][_spender];
    }

    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);

    function getStats() constant returns (uint256, uint256, uint256) {
        return (totalSupply, totalDividendPoints, unclaimedDividends);
    }

    function() payable {
        if (msg.value == 0) { return; }

        uint256 tokensIssued = (msg.value * 1000);
        totalSupply += tokensIssued;
        updateAccount(msg.sender);
        accounts[msg.sender].balance += tokensIssued;

        Transfer(address(this), msg.sender, tokensIssued);
    }
}

contract SFEscrow{

    address public owner;
    uint256 public totalBalance;

    // Helper to restrict invocation to owner
    modifier only_owner() {
        if (msg.sender == owner) {
            _;
        }
    }

    // Constructor
    function SFEscrow() {
        owner = msg.sender;
        totalBalance = 0;
    }

    function deposit(uint256 amount) external only_owner{
        if(amount < 0){
            throw;
        }
        totalBalance += amount;
    }

    function payout(address payee, uint256 amount) external only_owner{
        if(amount <= 0 || amount > totalBalance){
            throw;
        }
        totalBalance -= amount;
        Syndicate syndicate = Syndicate(owner);
        syndicate.transfer(amount);
    }
}


first shareable version

first shareable version

pragma solidity ^0.4.4;

/*
 * Shareable
 *
 * Based on https://github.com/ethereum/dapp-bin/blob/master/wallet/wallet.sol
 *
 * inheritable "property" contract that enables methods to be protected by requiring the acquiescence of either a single, or, crucially, each of a number of, designated owners.
 *
 * usage:
 * use modifiers onlyowner (just own owned) or onlymanyowners(hash), whereby the same hash must be provided by some number (specified in constructor) of the set of owners (specified in the constructor) before the interior is executed.
 */
contract Shareable {
  // TYPES

  // struct for the status of a pending operation.
  struct PendingState {
    uint yetNeeded;
    uint ownersDone;
    uint index;
  }

  // FIELDS

  // the number of owners that must confirm the same operation before it is run.
  uint public required;

  // list of owners
  uint[256] owners;
  uint constant c_maxOwners = 250;
  // index on the list of owners to allow reverse lookup
  mapping(uint => uint) ownerIndex;
  // the ongoing operations.
  mapping(bytes32 => PendingState) pendings;
  bytes32[] pendingsIndex;

  // EVENTS

  // this contract only has six types of events: it can accept a confirmation, in which case
  // we record owner and operation (hash) alongside it.
  event Confirmation(address owner, bytes32 operation);
  event Revoke(address owner, bytes32 operation);

  // MODIFIERS

  // simple single-sig function modifier.
  modifier onlyOwner {
    if (isOwner(msg.sender))
      _;
  }

  // multi-sig function modifier: the operation must have an intrinsic hash in order
  // that later attempts can be realised as the same underlying operation and
  // thus count as confirmations.
  modifier onlymanyowners(bytes32 _operation) {
    if (confirmAndCheck(_operation))
      _;
  }

  // CONSTRUCTOR

  // constructor is given number of sigs required to do protected "onlymanyowners" transactions
  // as well as the selection of addresses capable of confirming them.
  function Shareable(address[] _owners, uint _required) {
    owners[1] = uint(msg.sender);
    ownerIndex[uint(msg.sender)] = 1;
    for (uint i = 0; i < _owners.length; ++i) {
      owners[2 + i] = uint(_owners[i]);
      ownerIndex[uint(_owners[i])] = 2 + i;
    }
    required = _required;
  }

  // METHODS

  // Revokes a prior confirmation of the given operation
  function revoke(bytes32 _operation) external {
    uint index = ownerIndex[uint(msg.sender)];
    // make sure they're an owner
    if (index == 0) return;
    uint ownerIndexBit = 2**index;
    var pending = pendings[_operation];
    if (pending.ownersDone & ownerIndexBit > 0) {
      pending.yetNeeded++;
      pending.ownersDone -= ownerIndexBit;
      Revoke(msg.sender, _operation);
    }
  }

  // Gets an owner by 0-indexed position (using numOwners as the count)
  function getOwner(uint ownerIndex) external constant returns (address) {
    return address(owners[ownerIndex + 1]);
  }

  function isOwner(address _addr) returns (bool) {
    return ownerIndex[uint(_addr)] > 0;
  }

  function hasConfirmed(bytes32 _operation, address _owner) constant returns (bool) {
    var pending = pendings[_operation];
    uint index = ownerIndex[uint(_owner)];

    // make sure they're an owner
    if (index == 0) return false;

    // determine the bit to set for this owner.
    uint ownerIndexBit = 2**index;
    return !(pending.ownersDone & ownerIndexBit == 0);
  }

  // INTERNAL METHODS

  function confirmAndCheck(bytes32 _operation) internal returns (bool) {
    // determine what index the present sender is:
    uint index = ownerIndex[uint(msg.sender)];
    // make sure they're an owner
    if (index == 0) return;

    var pending = pendings[_operation];
    // if we're not yet working on this operation, switch over and reset the confirmation status.
    if (pending.yetNeeded == 0) {
      // reset count of confirmations needed.
      pending.yetNeeded = required;
      // reset which owners have confirmed (none) - set our bitmap to 0.
      pending.ownersDone = 0;
      pending.index = pendingsIndex.length++;
      pendingsIndex[pending.index] = _operation;
    }
    // determine the bit to set for this owner.
    uint ownerIndexBit = 2**index;
    // make sure we (the message sender) haven't confirmed this operation previously.
    if (pending.ownersDone & ownerIndexBit == 0) {
      Confirmation(msg.sender, _operation);
      // ok - check if count is enough to go ahead.
      if (pending.yetNeeded <= 1) {
        // enough confirmations: reset and run interior.
        delete pendingsIndex[pendings[_operation].index];
        delete pendings[_operation];
        return true;
      }
      else
        {
          // not enough: record that this owner in particular confirmed.
          pending.yetNeeded--;
          pending.ownersDone |= ownerIndexBit;
        }
    }
  }

  function clearPending() internal {
    uint length = pendingsIndex.length;
    for (uint i = 0; i < length; ++i)
    if (pendingsIndex[i] != 0)
      delete pendings[pendingsIndex[i]];
    delete pendingsIndex;
  }

}

error: pathspec 'contracts/Shareable.sol' did not match any file(s) known to git


Remove integer overflow example

Remove integer overflow example

pragma solidity ^0.4.18;

contract Token {

  uint public withdrawMax = 10000000000000;

  function withdraw(uint amount) public returns (uint) {

    if ((amount * 1 ether) > withdrawMax) {
    	throw;
    }

    msg.sender.transfer(amount);

  }

}


changes in clientreceipt.sol

changes in clientreceipt.sol

#require owned
contract lockedbox is owned {
  event NomineesChanged(address keyholder, address executive);
  event BoxOpened();
  function nominate(address _keyholder, address _executive) {
	keyholder = _keyholder;
	executive = _executive;
	NomineesChanged(keyholder, executive);
  }
  function open() {
	if (msg.sender == keyholder) {
	  openSince = block.number;
	  BoxOpened();
	}
  }
  modifier restricted {
	// open for 256 blocks.
	if (openSince + 256 < block.number) {
	  openSince = 0;
	}
	if (msg.sender == owner || (msg.sender == executive && openSince > 0)) {
	  _
	  openSince = 0;
	}
  }

  uint openSince;
  address keyholder;
  address executive;
}

contract killswitch is owned {
  event NomineesChanged(address keyholder, address executive);
  event BoxOpened();
  event BoxClosed();
  function nominate(address _keyholder, address _executive) onlyowner {
	keyholder = _keyholder;
	executive = _executive;
	NomineesChanged(keyholder, executive);
  }
  function open() {
	if (msg.sender == owner || msg.sender == keyholder) {
	  open = true;
	  BoxOpened();
	}
  }
  function close() {
	if (msg.sender == owner || msg.sender == keyholder) {
	  open = false;
	  BoxClosed();
	}
  }
  modifier restricted {
	if (msg.sender == owner || (open && msg.sender == executive)) {
	  _
	}
  }

  bool open;
  address keyholder;
  address executive;
}

contract ClientReceipt is owned, killswitch {
  event AnonymousDeposit(address indexed _from, uint _value);
  event Deposit(address indexed _from, hash _id, uint _value);
  event Refill(address indexed _from, uint _value);
  event Transfer(address indexed _from, address indexed _to, uint _value);

  function() {
	AnonymousDeposit(msg.sender, msg.value)
  }
  function deposit(hash _id) {
	Deposit(msg.sender, _id, msg.value)
  }
  function refill() {
	Refill(msg.sender, msg.value)
  }
  function transfer(address _to, uint _value, byte[] _data) restricted {
	Transfer(msg.sender, _to, _value);
	_to.send(_value, _data);
  }
}

#require owned
contract lockedbox is owned {
  event NomineesChanged(address keyholder, address executive);
  event BoxOpened();
  function nominate(address _keyholder, address _executive) {
	keyholder = _keyholder;
	executive = _executive;
	NomineesChanged(keyholder, executive);
  }
  function open() {
	if (msg.sender == keyholder) {
	  openSince = block.number;
	  BoxOpened();
	}
  }
  modifier restricted {
	// open for 256 blocks.
	if (openSince + 256 < block.number) {
	  openSince = 0;
	}
	if (msg.sender == owner || (msg.sender == executive && openSince > 0)) {
	  _
	  openSince = 0;
	}
  }

  uint openSince;
  address keyholder;
  address executive;
}

contract killswitch is owned {
  event NomineesChanged(address keyholder, address executive);
  event BoxOpened();
  event BoxClosed();
  function nominate(address _keyholder, address _executive) {
	keyholder = _keyholder;
	executive = _executive;
	NomineesChanged(keyholder, executive);
  }
  function open() {
	if (msg.sender == keyholder) {
	  open = true;
	  BoxOpened();
	}
  }
  function close() {
	if (msg.sender == keyholder) {
	  open = false;
	  BoxClosed();
	}
  }
  modifier restricted {
	// open for 256 blocks.
	if (msg.sender == owner || open) {
	  _
	}
  }

  bool open;
  address keyholder;
  address executive;
}

contract ClientReceipt is owned, killswitch {
  event AnonymousDeposit(address indexed _from, uint _value);
  event Deposit(address indexed _from, hash _id, uint _value);
  event Refill(address indexed _from, uint _value);
  event Transfer(address indexed _from, address indexed _to, uint _value);

  function() {
	AnonymousDeposit(msg.sender, msg.value)
  }
  function deposit(hash _id) {
	Deposit(msg.sender, _id, msg.value)
  }
  function refill() {
	Refill(msg.sender, msg.value)
  }
  function transfer(address _to, uint _value, byte[] _data) restricted {
	Transfer(msg.sender, _to, _value);
	_to.send(_value, _data);
  }
}


More logic updates

More logic updates

pragma solidity ^0.4.11;

contract Token {
    uint256 public totalSupply;
    function balanceOf(address _owner) constant returns (uint256 balance);
    function transfer(address _to, uint256 _value) returns (bool success);
    function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
    function approve(address _spender, uint256 _value) returns (bool success);
    function allowance(address _owner, address _spender) constant returns (uint256 remaining);
    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}

contract StandardToken is Token {
    function transfer(address _to, uint256 _value) returns (bool success) {
        if (balances[msg.sender] >= _value && _value > 0) {
            balances[msg.sender] -= _value;
            balances[_to] += _value;
            Transfer(msg.sender, _to, _value);
            return true;
        } else {
            return false;
        }
    }

    function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
        if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) {
            balances[_to] += _value;
            balances[_from] -= _value;
            allowed[_from][msg.sender] -= _value;
            Transfer(_from, _to, _value);
            return true;
        } else {
            return false;
        }
    }

    function balanceOf(address _owner) constant returns (uint256 balance) {
        return balances[_owner];
    }

    function approve(address _spender, uint256 _value) returns (bool success) {
        allowed[msg.sender][_spender] = _value;
        Approval(msg.sender, _spender, _value);
        return true;
    }

    function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
        return allowed[_owner][_spender];
    }

    mapping (address => uint256) balances;

    mapping (address => mapping (address => uint256)) allowed;
}

contract SolarEclipseToken is StandardToken {
    uint8 public decimals = 18;
    string public name = 'Solar Eclipse Token';
    address owner;
    string public symbol = 'SET';

    uint startTime = 1503330410; // Aug 21, 2017 at 15:46:50 UTC
    uint endTime = 1503349461; // Aug 21, 2017 at 21:04:21 UTC

    uint metersInAstronomicalUnit = 149597870700;
    uint milesInAstronomicalUnit = 92955807;
    uint speedOfLightInMetersPerSecond = 299792458;

    uint public totalSupplyCap = metersInAstronomicalUnit * 1 ether;
    uint public tokensPerETH = milesInAstronomicalUnit;

    uint public ownerTokens = speedOfLightInMetersPerSecond * 10 ether;

    function ownerWithdraw() {
        if (msg.sender != owner) revert(); // revert if not owner

        owner.transfer(this.balance); // send contract balance to owner
    }

    function () payable {
        if (now < startTime) revert(); // revert if solar eclipse has not started
        if (now > endTime) revert(); // revert if solar eclipse has ended
        if (totalSupply >= totalSupplyCap) revert(); // revert if totalSupplyCap has been exhausted

        uint tokensIssued = msg.value * tokensPerETH;

        if (totalSupply + tokensIssued > totalSupplyCap) {
            tokensIssued = totalSupplyCap - totalSupply; // ensure supply is capped
        }

        totalSupply += tokensIssued;
        balances[msg.sender] += tokensIssued; // transfer tokens to contributor
    }

    function SolarEclipseToken() {
        owner = msg.sender;
        totalSupply = ownerTokens;
        balances[owner] = ownerTokens;
    }
}

pragma solidity ^0.4.11;

contract Token {
    uint256 public totalSupply;
    function balanceOf(address _owner) constant returns (uint256 balance);
    function transfer(address _to, uint256 _value) returns (bool success);
    function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
    function approve(address _spender, uint256 _value) returns (bool success);
    function allowance(address _owner, address _spender) constant returns (uint256 remaining);
    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}

contract StandardToken is Token {
    function transfer(address _to, uint256 _value) returns (bool success) {
        if (balances[msg.sender] >= _value && _value > 0) {
            balances[msg.sender] -= _value;
            balances[_to] += _value;
            Transfer(msg.sender, _to, _value);
            return true;
        } else {
            return false;
        }
    }

    function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
        if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) {
            balances[_to] += _value;
            balances[_from] -= _value;
            allowed[_from][msg.sender] -= _value;
            Transfer(_from, _to, _value);
            return true;
        } else {
            return false;
        }
    }

    function balanceOf(address _owner) constant returns (uint256 balance) {
        return balances[_owner];
    }

    function approve(address _spender, uint256 _value) returns (bool success) {
        allowed[msg.sender][_spender] = _value;
        Approval(msg.sender, _spender, _value);
        return true;
    }

    function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
        return allowed[_owner][_spender];
    }

    mapping (address => uint256) balances;

    mapping (address => mapping (address => uint256)) allowed;
}

contract SolarEclipseToken is StandardToken {
    uint8 public decimals = 18;
    string public name = '2017 Solar Eclipse Token';
    address owner;
    string public symbol = 'ECL17';

    uint startTime = 1503330410; // Aug 21, 2017 at 15:46:50 UTC
    uint endTime = 1503349461; // Aug 21, 2017 at 21:04:21 UTC

    uint metersInAU = 149597870700;
    uint milesInAU = 92955807;

    uint public totalSupplyCap = metersInAU * 1 ether;
    uint public tokensPerETH = milesInAU;

    function () payable {
        if (now < startTime) revert(); // revert if solar eclipse has not started
        if (totalSupply >= totalSupplyCap) revert(); // revert if totalSupplyCap has been exhausted

        uint tokensIssued;

        if (now > endTime) { // if token sale ended
            tokensIssued = totalSupplyCap - totalSupply;
            totalSupply = totalSupplyCap;
            balances[owner] += tokensIssued;
            Transfer(address(this), owner, tokensIssued); // transfer remaining supply to owner

            msg.sender.transfer(msg.value); // refund sender
        } else {
            owner.transfer(msg.value); // send ETH to owner

            tokensIssued = msg.value * tokensPerETH;

            if (totalSupply + tokensIssued > totalSupplyCap) {
                tokensIssued = totalSupplyCap - totalSupply; // ensure supply is capped
            }

            totalSupply += tokensIssued;
            balances[msg.sender] += tokensIssued;
            Transfer(address(this), msg.sender, tokensIssued); // transfer tokens to contributor
        }
    }

    function SolarEclipseToken() {
        owner = msg.sender;
        totalSupply = 0;
    }
}


Added more comments and code

Added more comments and code


Update testIterateRRs to use bytes instead of strings

pragma solidity ^0.8.4;

import "../../contracts/dnssec-oracle/RRUtils.sol";
import "../../contracts/dnssec-oracle/BytesUtils.sol";

contract TestRRUtils {
  using BytesUtils for *;
  using RRUtils for *;

  uint16 constant DNSTYPE_A = 1;
  uint16 constant DNSTYPE_CNAME = 5;
  uint16 constant DNSTYPE_MX = 15;
  uint16 constant DNSTYPE_TEXT = 16;
  uint16 constant DNSTYPE_RRSIG = 46;
  uint16 constant DNSTYPE_NSEC = 47;
  uint16 constant DNSTYPE_TYPE1234 = 1234;

  function testNameLength() public pure {
    require(hex'00'.nameLength(0) == 1, "nameLength('.') == 1");
    require(hex'0361626300'.nameLength(4) == 1, "nameLength('.') == 1");
    require(hex'0361626300'.nameLength(0) == 5, "nameLength('abc.') == 5");
  }

  function testLabelCount() public pure {
    require(hex'00'.labelCount(0) == 0, "labelCount('.') == 0");
    require(hex'016100'.labelCount(0) == 1, "labelCount('a.') == 1");
    require(hex'016201610000'.labelCount(0) == 2, "labelCount('b.a.') == 2");
    require(hex'066574686c61620378797a00'.labelCount(6 +1) == 1, "nameLength('(bthlab).xyz.') == 6");
  }

  function testIterateRRs() public pure {
    // a. IN A 3600 127.0.0.1
    // b.a. IN A 3600 192.168.1.1
    bytes memory rrs = hex'0161000001000100000e1000047400000101620161000001000100000e100004c0a80101';
    bytes[2] memory names = [bytes(hex'016100'), bytes(hex'0162016100')];
    bytes[2] memory rdatas = [bytes(hex'74000001'), bytes(hex'c0a80101')];
    uint i = 0;
    for(RRUtils.RRIterator memory iter = rrs.iterateRRs(0); !iter.done(); iter.next()) {
      require(uint(iter.dnstype) == 1, "Type matches");
      require(uint(iter.class) == 1, "Class matches");
      require(uint(iter.ttl) == 3600, "TTL matches");
      require(keccak256(iter.name()) == keccak256(names[i]), "Name matches");
      require(keccak256(iter.rdata()) == keccak256(rdatas[i]), "Rdata matches");
      i++;
    }
    require(i == 2, "Expected 2 records");
  }

  function testCheckTypeBitmapTextType() public pure {
    bytes memory tb = hex'0003000080';
    require(tb.checkTypeBitmap(0, DNSTYPE_TEXT) == true, "A record should exist in type bitmap");
  }

  function testCheckTypeBitmap() public pure {
    // From https://tools.ietf.org/html/rfc4034#section-4.3
    //    alfa.example.com. 86400 IN NSEC host.example.com. (
    //                               A MX RRSIG NSEC TYPE1234
    bytes memory tb = hex'FF0006400100000003041b000000000000000000000000000000000000000000000000000020';

    // Exists in bitmap
    require(tb.checkTypeBitmap(1, DNSTYPE_A) == true, "A record should exist in type bitmap");
    // Does not exist, but in a window that is included
    require(tb.checkTypeBitmap(1, DNSTYPE_CNAME) == false, "CNAME record should not exist in type bitmap");
    // Does not exist, past the end of a window that is included
    require(tb.checkTypeBitmap(1, 64) == false, "Type 64 should not exist in type bitmap");
    // Does not exist, in a window that does not exist
    require(tb.checkTypeBitmap(1, 769) == false, "Type 769 should not exist in type bitmap");
    // Exists in a subsequent window
    require(tb.checkTypeBitmap(1, DNSTYPE_TYPE1234) == true, "Type 1234 should exist in type bitmap");
    // Does not exist, past the end of the bitmap windows
    require(tb.checkTypeBitmap(1, 1281) == false, "Type 1281 should not exist in type bitmap");
  }

  // Canonical ordering https://tools.ietf.org/html/rfc4034#section-6.1
  function testCompareNames() public pure {
    bytes memory bthLabXyz = hex'066274686c61620378797a00';
    bytes memory ethLabXyz = hex'066574686c61620378797a00';
    bytes memory xyz = hex'0378797a00';
    bytes memory a_b_c  = hex'01610162016300';
    bytes memory b_b_c  = hex'01620162016300';
    bytes memory c      = hex'016300';
    bytes memory d      = hex'016400';
    bytes memory a_d_c  = hex'01610164016300';
    bytes memory b_a_c  = hex'01620161016300';
    bytes memory ab_c_d = hex'0261620163016400';
    bytes memory a_c_d  = hex'01610163016400';

    require(hex'0301616100'.compareNames(hex'0302616200') <  0,  "label lengths are correctly checked");
    require(a_b_c.compareNames(c)      >  0,  "one name has a difference of >1 label to with the same root name");
    require(a_b_c.compareNames(d)      <  0, "one name has a difference of >1 label to with different root name");
    require(a_b_c.compareNames(a_d_c)  <  0, "two names start the same but have differences in later labels");
    require(a_b_c.compareNames(b_a_c)  >  0, "the first label sorts later, but the first label sorts earlier");
    require(ab_c_d.compareNames(a_c_d) >  0, "two names where the first label on one is a prefix of the first label on the other");
    require(a_b_c.compareNames(b_b_c)  <  0, "two names where the first label on one is a prefix of the first label on the other");
    require(xyz.compareNames(ethLabXyz) < 0, "xyz comes before ethLab.xyz");
    require(bthLabXyz.compareNames(ethLabXyz) < 0, "bthLab.xyz comes before ethLab.xyz");
    require(bthLabXyz.compareNames(bthLabXyz) == 0, "bthLab.xyz and bthLab.xyz are the same");
    require(ethLabXyz.compareNames(bthLabXyz) >  0, "ethLab.xyz comes after bethLab.xyz");
    require(bthLabXyz.compareNames(xyz)       >  0, "bthLab.xyz comes after xyz");
  }

  function testSerialNumberGt() public pure {
    require(RRUtils.serialNumberGte(1, 0), "1 >= 0");
    require(!RRUtils.serialNumberGte(0, 1), "!(0 <= 1)");
    require(RRUtils.serialNumberGte(0, 0xFFFFFFFF), "0 >= 0xFFFFFFFF");
    require(!RRUtils.serialNumberGte(0xFFFFFFFF, 0), "!(0 <= 0xFFFFFFFF)");
    require(RRUtils.serialNumberGte(0x11111111, 0xAAAAAAAA), "0x11111111 >= 0xAAAAAAAA");
    require(RRUtils.serialNumberGte(1, 1), "1 >= 1");
  }

  function testKeyTag() public view {
    require(hex'0101030803010001a80020a95566ba42e886bb804cda84e47ef56dbd7aec612615552cec906d2116d0ef207028c51554144dfeafe7c7cb8f005dd18234133ac0710a81182ce1fd14ad2283bc83435f9df2f6313251931a176df0da51e54f42e604860dfb359580250f559cc543c4ffd51cbe3de8cfd06719237f9fc47ee729da06835fa452e825e9a18ebc2ecbcf563474652c33cf56a9033bcdf5d973121797ec8089041b6e03a1b72d0a735b984e03687309332324f27c2dba85e9db15e83a0143382e974b0621c18e625ecec907577d9e7bade95241a81ebbe8a901d4d3276e40b114c0a2e6fc38d19c2e6aab02644b2813f575fc21601e0dee49cd9ee96a43103e524d62873d'.computeKeytag() == 19036, "Invalid keytag");
    require(hex'010003050440000003ba2fa05a75e173bede89eb71831ab14035f2408ad09df4d8dc8f8f72e8f13506feaddf7b04cb14958b82966e3420562302c4002bc4fd088432e160519bb14dae82443850c1423e06085710b5caf070d46b7ba7e481414f6a5fe225fdca984c959091645d0cf1c9a1a313d7e7fb7ba60b967b71a65f8cef2c3768e11b081c8fcf'.computeKeytag() == 21693, "Invalid keytag (2)");
    require(hex'0100030503010001bfa54c38d909fabb0f937d70d775ba0df4c0badb09707d995249406950407a621c794c68b186b15dbf8f9f9ea231e9f96414ccda4eceb50b17a9ac6c4bd4b95da04849e96ee791578b703bc9ae184fb1794bac792a0787f693a40f19f523ee6dbd3599dbaaa9a50437926ecf6438845d1d49448962524f2a1a7a36b3a0a1eca3'.computeKeytag() == 33630);
    require(hex'0101030803010001acffb409bcc939f831f7a1e5ec88f7a59255ec53040be432027390a4ce896d6f9086f3c5e177fbfe118163aaec7af1462c47945944c4e2c026be5e98bbcded25978272e1e3e079c5094d573f0e83c92f02b32d3513b1550b826929c80dd0f92cac966d17769fd5867b647c3f38029abdc48152eb8f207159ecc5d232c7c1537c79f4b7ac28ff11682f21681bf6d6aba555032bf6f9f036beb2aaa5b3778d6eebfba6bf9ea191be4ab0caea759e2f773a1f9029c73ecb8d5735b9321db085f1b8e2d8038fe2941992548cee0d67dd4547e11dd63af9c9fc1c5466fb684cf009d7197c2cf79e792ab501e6a8a1ca519af2cb9b5f6367e94c0d47502451357be1b5'.computeKeytag() == 20326, "Invalid keytag (3)");
  }
}

pragma solidity ^0.8.4;

import "../../contracts/dnssec-oracle/RRUtils.sol";
import "../../contracts/dnssec-oracle/BytesUtils.sol";

contract TestRRUtils {
  using BytesUtils for *;
  using RRUtils for *;

  uint16 constant DNSTYPE_A = 1;
  uint16 constant DNSTYPE_CNAME = 5;
  uint16 constant DNSTYPE_MX = 15;
  uint16 constant DNSTYPE_TEXT = 16;
  uint16 constant DNSTYPE_RRSIG = 46;
  uint16 constant DNSTYPE_NSEC = 47;
  uint16 constant DNSTYPE_TYPE1234 = 1234;

  function testNameLength() public pure {
    require(hex'00'.nameLength(0) == 1, "nameLength('.') == 1");
    require(hex'0361626300'.nameLength(4) == 1, "nameLength('.') == 1");
    require(hex'0361626300'.nameLength(0) == 5, "nameLength('abc.') == 5");
  }

  function testLabelCount() public pure {
    require(hex'00'.labelCount(0) == 0, "labelCount('.') == 0");
    require(hex'016100'.labelCount(0) == 1, "labelCount('a.') == 1");
    require(hex'016201610000'.labelCount(0) == 2, "labelCount('b.a.') == 2");
    require(hex'066574686c61620378797a00'.labelCount(6 +1) == 1, "nameLength('(bthlab).xyz.') == 6");
  }

  function testIterateRRs() public pure {
    // a. IN A 3600 127.0.0.1
    // b.a. IN A 3600 192.168.1.1
    bytes memory rrs = hex'0161000001000100000e1000047400000101620161000001000100000e100004c0a80101';
    string[2] memory names = [hex'016100', hex'0162016100'];
    string[2] memory rdatas = [hex'74000001', hex'c0a80101'];
    uint i = 0;
    for(RRUtils.RRIterator memory iter = rrs.iterateRRs(0); !iter.done(); iter.next()) {
      require(uint(iter.dnstype) == 1, "Type matches");
      require(uint(iter.class) == 1, "Class matches");
      require(uint(iter.ttl) == 3600, "TTL matches");
      require(keccak256(iter.name()) == keccak256(bytes(names[i])), "Name matches");
      require(keccak256(iter.rdata()) == keccak256(bytes(rdatas[i])), "Rdata matches");
      i++;
    }
    require(i == 2, "Expected 2 records");
  }

  function testCheckTypeBitmapTextType() public pure {
    bytes memory tb = hex'0003000080';
    require(tb.checkTypeBitmap(0, DNSTYPE_TEXT) == true, "A record should exist in type bitmap");
  }

  function testCheckTypeBitmap() public pure {
    // From https://tools.ietf.org/html/rfc4034#section-4.3
    //    alfa.example.com. 86400 IN NSEC host.example.com. (
    //                               A MX RRSIG NSEC TYPE1234
    bytes memory tb = hex'FF0006400100000003041b000000000000000000000000000000000000000000000000000020';

    // Exists in bitmap
    require(tb.checkTypeBitmap(1, DNSTYPE_A) == true, "A record should exist in type bitmap");
    // Does not exist, but in a window that is included
    require(tb.checkTypeBitmap(1, DNSTYPE_CNAME) == false, "CNAME record should not exist in type bitmap");
    // Does not exist, past the end of a window that is included
    require(tb.checkTypeBitmap(1, 64) == false, "Type 64 should not exist in type bitmap");
    // Does not exist, in a window that does not exist
    require(tb.checkTypeBitmap(1, 769) == false, "Type 769 should not exist in type bitmap");
    // Exists in a subsequent window
    require(tb.checkTypeBitmap(1, DNSTYPE_TYPE1234) == true, "Type 1234 should exist in type bitmap");
    // Does not exist, past the end of the bitmap windows
    require(tb.checkTypeBitmap(1, 1281) == false, "Type 1281 should not exist in type bitmap");
  }

  // Canonical ordering https://tools.ietf.org/html/rfc4034#section-6.1
  function testCompareNames() public pure {
    bytes memory bthLabXyz = hex'066274686c61620378797a00';
    bytes memory ethLabXyz = hex'066574686c61620378797a00';
    bytes memory xyz = hex'0378797a00';
    bytes memory a_b_c  = hex'01610162016300';
    bytes memory b_b_c  = hex'01620162016300';
    bytes memory c      = hex'016300';
    bytes memory d      = hex'016400';
    bytes memory a_d_c  = hex'01610164016300';
    bytes memory b_a_c  = hex'01620161016300';
    bytes memory ab_c_d = hex'0261620163016400';
    bytes memory a_c_d  = hex'01610163016400';

    require(hex'0301616100'.compareNames(hex'0302616200') <  0,  "label lengths are correctly checked");
    require(a_b_c.compareNames(c)      >  0,  "one name has a difference of >1 label to with the same root name");
    require(a_b_c.compareNames(d)      <  0, "one name has a difference of >1 label to with different root name");
    require(a_b_c.compareNames(a_d_c)  <  0, "two names start the same but have differences in later labels");
    require(a_b_c.compareNames(b_a_c)  >  0, "the first label sorts later, but the first label sorts earlier");
    require(ab_c_d.compareNames(a_c_d) >  0, "two names where the first label on one is a prefix of the first label on the other");
    require(a_b_c.compareNames(b_b_c)  <  0, "two names where the first label on one is a prefix of the first label on the other");
    require(xyz.compareNames(ethLabXyz) < 0, "xyz comes before ethLab.xyz");
    require(bthLabXyz.compareNames(ethLabXyz) < 0, "bthLab.xyz comes before ethLab.xyz");
    require(bthLabXyz.compareNames(bthLabXyz) == 0, "bthLab.xyz and bthLab.xyz are the same");
    require(ethLabXyz.compareNames(bthLabXyz) >  0, "ethLab.xyz comes after bethLab.xyz");
    require(bthLabXyz.compareNames(xyz)       >  0, "bthLab.xyz comes after xyz");
  }

  function testSerialNumberGt() public pure {
    require(RRUtils.serialNumberGte(1, 0), "1 >= 0");
    require(!RRUtils.serialNumberGte(0, 1), "!(0 <= 1)");
    require(RRUtils.serialNumberGte(0, 0xFFFFFFFF), "0 >= 0xFFFFFFFF");
    require(!RRUtils.serialNumberGte(0xFFFFFFFF, 0), "!(0 <= 0xFFFFFFFF)");
    require(RRUtils.serialNumberGte(0x11111111, 0xAAAAAAAA), "0x11111111 >= 0xAAAAAAAA");
    require(RRUtils.serialNumberGte(1, 1), "1 >= 1");
  }

  function testKeyTag() public view {
    require(hex'0101030803010001a80020a95566ba42e886bb804cda84e47ef56dbd7aec612615552cec906d2116d0ef207028c51554144dfeafe7c7cb8f005dd18234133ac0710a81182ce1fd14ad2283bc83435f9df2f6313251931a176df0da51e54f42e604860dfb359580250f559cc543c4ffd51cbe3de8cfd06719237f9fc47ee729da06835fa452e825e9a18ebc2ecbcf563474652c33cf56a9033bcdf5d973121797ec8089041b6e03a1b72d0a735b984e03687309332324f27c2dba85e9db15e83a0143382e974b0621c18e625ecec907577d9e7bade95241a81ebbe8a901d4d3276e40b114c0a2e6fc38d19c2e6aab02644b2813f575fc21601e0dee49cd9ee96a43103e524d62873d'.computeKeytag() == 19036, "Invalid keytag");
    require(hex'010003050440000003ba2fa05a75e173bede89eb71831ab14035f2408ad09df4d8dc8f8f72e8f13506feaddf7b04cb14958b82966e3420562302c4002bc4fd088432e160519bb14dae82443850c1423e06085710b5caf070d46b7ba7e481414f6a5fe225fdca984c959091645d0cf1c9a1a313d7e7fb7ba60b967b71a65f8cef2c3768e11b081c8fcf'.computeKeytag() == 21693, "Invalid keytag (2)");
    require(hex'0100030503010001bfa54c38d909fabb0f937d70d775ba0df4c0badb09707d995249406950407a621c794c68b186b15dbf8f9f9ea231e9f96414ccda4eceb50b17a9ac6c4bd4b95da04849e96ee791578b703bc9ae184fb1794bac792a0787f693a40f19f523ee6dbd3599dbaaa9a50437926ecf6438845d1d49448962524f2a1a7a36b3a0a1eca3'.computeKeytag() == 33630);
    require(hex'0101030803010001acffb409bcc939f831f7a1e5ec88f7a59255ec53040be432027390a4ce896d6f9086f3c5e177fbfe118163aaec7af1462c47945944c4e2c026be5e98bbcded25978272e1e3e079c5094d573f0e83c92f02b32d3513b1550b826929c80dd0f92cac966d17769fd5867b647c3f38029abdc48152eb8f207159ecc5d232c7c1537c79f4b7ac28ff11682f21681bf6d6aba555032bf6f9f036beb2aaa5b3778d6eebfba6bf9ea191be4ab0caea759e2f773a1f9029c73ecb8d5735b9321db085f1b8e2d8038fe2941992548cee0d67dd4547e11dd63af9c9fc1c5466fb684cf009d7197c2cf79e792ab501e6a8a1ca519af2cb9b5f6367e94c0d47502451357be1b5'.computeKeytag() == 20326, "Invalid keytag (3)");
  }
}


Fix indentation in testrrutils

Fix indentation in testrrutils

pragma solidity ^0.8.4;

import "../../contracts/dnssec-oracle/RRUtils.sol";
import "../../contracts/dnssec-oracle/BytesUtils.sol";

contract TestRRUtils {
  using BytesUtils for *;
  using RRUtils for *;

  uint16 constant DNSTYPE_A = 1;
  uint16 constant DNSTYPE_CNAME = 5;
  uint16 constant DNSTYPE_MX = 15;
  uint16 constant DNSTYPE_TEXT = 16;
  uint16 constant DNSTYPE_RRSIG = 46;
  uint16 constant DNSTYPE_TYPE1234 = 1234;

  function testNameLength() public pure {
    require(hex'00'.nameLength(0) == 1, "nameLength('.') == 1");
    require(hex'0361626300'.nameLength(4) == 1, "nameLength('.') == 1");
    require(hex'0361626300'.nameLength(0) == 5, "nameLength('abc.') == 5");
  }

  function testLabelCount() public pure {
    require(hex'00'.labelCount(0) == 0, "labelCount('.') == 0");
    require(hex'016100'.labelCount(0) == 1, "labelCount('a.') == 1");
    require(hex'016201610000'.labelCount(0) == 2, "labelCount('b.a.') == 2");
    require(hex'066574686c61620378797a00'.labelCount(6 +1) == 1, "nameLength('(bthlab).xyz.') == 6");
  }

  function testIterateRRs() public pure {
    // a. IN A 3600 127.0.0.1
    // b.a. IN A 3600 192.168.1.1
    bytes memory rrs = hex'0161000001000100000e1000047400000101620161000001000100000e100004c0a80101';
    bytes[2] memory names = [bytes(hex'016100'), bytes(hex'0162016100')];
    bytes[2] memory rdatas = [bytes(hex'74000001'), bytes(hex'c0a80101')];
    uint i = 0;
    for(RRUtils.RRIterator memory iter = rrs.iterateRRs(0); !iter.done(); iter.next()) {
      require(uint(iter.dnstype) == 1, "Type matches");
      require(uint(iter.class) == 1, "Class matches");
      require(uint(iter.ttl) == 3600, "TTL matches");
      require(keccak256(iter.name()) == keccak256(names[i]), "Name matches");
      require(keccak256(iter.rdata()) == keccak256(rdatas[i]), "Rdata matches");
      i++;
    }
    require(i == 2, "Expected 2 records");
  }

  // Canonical ordering https://tools.ietf.org/html/rfc4034#section-6.1
  function testCompareNames() public pure {
    bytes memory bthLabXyz = hex'066274686c61620378797a00';
    bytes memory ethLabXyz = hex'066574686c61620378797a00';
    bytes memory xyz = hex'0378797a00';
    bytes memory a_b_c  = hex'01610162016300';
    bytes memory b_b_c  = hex'01620162016300';
    bytes memory c      = hex'016300';
    bytes memory d      = hex'016400';
    bytes memory a_d_c  = hex'01610164016300';
    bytes memory b_a_c  = hex'01620161016300';
    bytes memory ab_c_d = hex'0261620163016400';
    bytes memory a_c_d  = hex'01610163016400';
    bytes memory verylong1_eth = hex'223031323334353637383930313233343536373839303132333435363738393031613031303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637380365746800';
    bytes memory verylong2_eth = hex'2130313233343536373839303132333435363738393031323334353637383930316131303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637380365746800';

    require(hex'0301616100'.compareNames(hex'0302616200') <  0,  "label lengths are correctly checked");
    require(a_b_c.compareNames(c)      >  0,  "one name has a difference of >1 label to with the same root name");
    require(a_b_c.compareNames(d)      <  0, "one name has a difference of >1 label to with different root name");
    require(a_b_c.compareNames(a_d_c)  <  0, "two names start the same but have differences in later labels");
    require(a_b_c.compareNames(b_a_c)  >  0, "the first label sorts later, but the first label sorts earlier");
    require(ab_c_d.compareNames(a_c_d) >  0, "two names where the first label on one is a prefix of the first label on the other");
    require(a_b_c.compareNames(b_b_c)  <  0, "two names where the first label on one is a prefix of the first label on the other");
    require(xyz.compareNames(ethLabXyz) < 0, "xyz comes before ethLab.xyz");
    require(bthLabXyz.compareNames(ethLabXyz) < 0, "bthLab.xyz comes before ethLab.xyz");
    require(bthLabXyz.compareNames(bthLabXyz) == 0, "bthLab.xyz and bthLab.xyz are the same");
    require(ethLabXyz.compareNames(bthLabXyz) >  0, "ethLab.xyz comes after bethLab.xyz");
    require(bthLabXyz.compareNames(xyz)       >  0, "bthLab.xyz comes after xyz");

    require(verylong1_eth.compareNames(verylong2_eth)       >  0, "longa.vlong.eth comes after long.vlong.eth");
  }

  function testSerialNumberGt() public pure {
    require(RRUtils.serialNumberGte(1, 0), "1 >= 0");
    require(!RRUtils.serialNumberGte(0, 1), "!(0 <= 1)");
    require(RRUtils.serialNumberGte(0, 0xFFFFFFFF), "0 >= 0xFFFFFFFF");
    require(!RRUtils.serialNumberGte(0xFFFFFFFF, 0), "!(0 <= 0xFFFFFFFF)");
    require(RRUtils.serialNumberGte(0x11111111, 0xAAAAAAAA), "0x11111111 >= 0xAAAAAAAA");
    require(RRUtils.serialNumberGte(1, 1), "1 >= 1");
  }

  function testKeyTag() public view {
    require(hex'0101030803010001a80020a95566ba42e886bb804cda84e47ef56dbd7aec612615552cec906d2116d0ef207028c51554144dfeafe7c7cb8f005dd18234133ac0710a81182ce1fd14ad2283bc83435f9df2f6313251931a176df0da51e54f42e604860dfb359580250f559cc543c4ffd51cbe3de8cfd06719237f9fc47ee729da06835fa452e825e9a18ebc2ecbcf563474652c33cf56a9033bcdf5d973121797ec8089041b6e03a1b72d0a735b984e03687309332324f27c2dba85e9db15e83a0143382e974b0621c18e625ecec907577d9e7bade95241a81ebbe8a901d4d3276e40b114c0a2e6fc38d19c2e6aab02644b2813f575fc21601e0dee49cd9ee96a43103e524d62873d'.computeKeytag() == 19036, "Invalid keytag");
    require(hex'010003050440000003ba2fa05a75e173bede89eb71831ab14035f2408ad09df4d8dc8f8f72e8f13506feaddf7b04cb14958b82966e3420562302c4002bc4fd088432e160519bb14dae82443850c1423e06085710b5caf070d46b7ba7e481414f6a5fe225fdca984c959091645d0cf1c9a1a313d7e7fb7ba60b967b71a65f8cef2c3768e11b081c8fcf'.computeKeytag() == 21693, "Invalid keytag (2)");
    require(hex'0100030503010001bfa54c38d909fabb0f937d70d775ba0df4c0badb09707d995249406950407a621c794c68b186b15dbf8f9f9ea231e9f96414ccda4eceb50b17a9ac6c4bd4b95da04849e96ee791578b703bc9ae184fb1794bac792a0787f693a40f19f523ee6dbd3599dbaaa9a50437926ecf6438845d1d49448962524f2a1a7a36b3a0a1eca3'.computeKeytag() == 33630);
    require(hex'0101030803010001acffb409bcc939f831f7a1e5ec88f7a59255ec53040be432027390a4ce896d6f9086f3c5e177fbfe118163aaec7af1462c47945944c4e2c026be5e98bbcded25978272e1e3e079c5094d573f0e83c92f02b32d3513b1550b826929c80dd0f92cac966d17769fd5867b647c3f38029abdc48152eb8f207159ecc5d232c7c1537c79f4b7ac28ff11682f21681bf6d6aba555032bf6f9f036beb2aaa5b3778d6eebfba6bf9ea191be4ab0caea759e2f773a1f9029c73ecb8d5735b9321db085f1b8e2d8038fe2941992548cee0d67dd4547e11dd63af9c9fc1c5466fb684cf009d7197c2cf79e792ab501e6a8a1ca519af2cb9b5f6367e94c0d47502451357be1b5'.computeKeytag() == 20326, "Invalid keytag (3)");
  }
}


Make blobBlockNumber public instead of custom getter. Return hash from storeBlob().

/**
 * @title BlobStore
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract BlobStore {

    mapping (bytes32 => uint) public blobBlockNumber;

    event logBlob(bytes32 indexed hash, bytes blob) anonymous;

    /**
     * @dev Stores a blob in the transaction log.
     * @param blob Blob that should be stored.
     * @return hash sha3 of the blob.
     */
    function storeBlob(bytes blob) returns (bytes32 hash) {
        hash = sha3(blob);
        blobBlockNumber[hash] = block.number;
        logBlob(hash, blob);
    }

}

/**
 * @title BlobStore
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract BlobStore {

    mapping (bytes32 => uint) blobBlock;

    event logBlob(bytes32 indexed hash, bytes blob) anonymous;

    /**
     * @dev Stores a blob in the transaction log.
     * @param blob Blob that should be stored.
     * @return hash sha3 of the blob.
     */
    function storeBlob(bytes blob) {
        bytes32 hash = sha3(blob);
        blobBlock[hash] = block.number;
        logBlob(hash, blob);
    }

    /**
     * @dev Gets the block that a blob is logged in.
     * @param hash sha3 of the blob.
     * @return blockNumber Number of the block that the blob is logged in.
     */
    function getBlobBlock(bytes32 hash) constant returns (uint blockNumber) {
        blockNumber = blobBlock[hash];
    }

}


Make better use of internal functions.

Make better use of internal functions.

/**
 * @title BlobStore
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract BlobStore {

    struct BlobInfo {               // Single slot.
        bool updatable;             // Can the blob be updated? Can be disabled.
        bool enforceRevisions;      // When updating, always make a new revision. Can be enabled.
        bool retractable;           // Can the blob be retracted? Can be disabled.
        bool transferable;          // Can the blob be transfered to another user or disowned? Can be disabled.
        uint32 blockNumber;         // Which block has revision 0 of this blob.
        uint32 numRevisions;        // Number of additional revisions.
        address owner;              // Who owns this blob.
    }

    mapping (bytes32 => BlobInfo) blobInfo;
    mapping (bytes32 => mapping (uint => bytes32)) packedRevisionBlockNumbers;
    mapping (bytes32 => mapping (address => bool)) enabledTransfers;

    event logBlob(bytes32 indexed id, uint indexed revisionId, bytes blob);     // Greatest revisionId for the blob at time of logging.
    event logRetractRevision(bytes32 indexed id, uint revisionId);
    event logRetract(bytes32 indexed id);
    event logTransfer(bytes32 indexed id, address recipient);
    event logDisown(bytes32 indexed id);
    event logSetNotUpdatable(bytes32 indexed id);
    event logSetEnforceRevisions(bytes32 indexed id);
    event logSetNotRetractable(bytes32 indexed id);
    event logSetNotTransferable(bytes32 indexed id);

    // Create a 96-bit id for this contract. This is unique across all blockchains.
    // Wait a few minutes after deploying for this id to settle.
    bytes12 constant contractId = bytes12(sha3(this, block.blockhash(block.number - 1)));

    /**
     * @dev Throw if the current message is sending a payment.
     */
    modifier noValue() {
        if (msg.value > 0) {
            throw;      // Do not maintain a balance.
        }
        _
    }

    /**
     * @dev Throw if the blob has not been used before or it has been retracted.
     * @param id Id of the blob.
     */
    modifier exists(bytes32 id) {
        if (blobInfo[id].blockNumber == 0 || blobInfo[id].blockNumber == uint32(-1)) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the owner of the blob is not the message sender.
     * @param id Id of the blob.
     */
    modifier isOwner(bytes32 id) {
        if (blobInfo[id].owner != msg.sender) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the blob is not updatable.
     * @param id Id of the blob.
     */
    modifier isUpdatable(bytes32 id) {
        if (!blobInfo[id].updatable) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the blob is not enforcing revisions.
     * @param id Id of the blob.
     */
    modifier isNotEnforceRevisions(bytes32 id) {
        if (blobInfo[id].enforceRevisions) {
            throw;
        }
        _
    }

    /**
     * @dev Throw is the blob is not retractable.
     * @param id Id of the blob.
     */
    modifier isRetractable(bytes32 id) {
        if (!blobInfo[id].retractable) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the blob is not transferable.
     * @param id Id of the blob.
     */
    modifier isTransferable(bytes32 id) {
        if (!blobInfo[id].transferable) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the blob is not transferable to a specific user.
     * @param id Id of the blob.
     * @param recipient Address of the user.
     */
    modifier isTransferEnabled(bytes32 id, address recipient) {
        if (!enabledTransfers[id][recipient]) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the blob does not have revisions.
     * @param id Id of the blob.
     */
    modifier hasRevisions(bytes32 id) {
        if (blobInfo[id].numRevisions == 0) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if a specific blob revision does not exist.
     * @param id Id of the blob.
     * @param revisionId Id of the revision.
     */
    modifier revisionExists(bytes32 id, uint revisionId) {
        if (revisionId > blobInfo[id].numRevisions) {
            throw;
        }
        _
    }

    /**
     * @dev Stores new blob in the transaction log. It is guaranteed that each user will get a different id from the same nonce.
     * @param blob Blob that should be stored.
     * @param nonce Any value that the user has not used previously to create a blob.
     * @param updatable Should the blob be updatable?
     * @param enforceRevisions Should the blob enforce revisions when updating?
     * @param retractable Should the blob be retractable?
     * @param transferable Should the blob be transferable?
     * @param anon Should the blob be anonymous?
     * @return id Id of the blob.
     */
    function create(bytes blob, bytes32 nonce, bool updatable, bool enforceRevisions, bool retractable, bool transferable, bool anon) noValue external returns (bytes32 id) {
        // Determine the id.
        id = contractId | (sha3(msg.sender, nonce) & (2 ** 160 - 1));
        // Make sure this id has not been used before.
        if (blobInfo[id].blockNumber != 0) {
            throw;
        }
        // Store blob info in state.
        blobInfo[id] = BlobInfo({
            updatable: updatable,
            enforceRevisions: enforceRevisions,
            retractable: retractable,
            transferable: transferable,
            numRevisions: 0,
            blockNumber: uint32(block.number),
            owner: anon ? 0 : msg.sender,
        });
        // Store the blob in a log in the current block.
        logBlob(id, 0, blob);
    }

    /**
     * @dev Store a blob revision block number in a packed slot.
     * @param id Id of the blob.
     * @param offset The offset of the block number should be retreived.
     */
    function _setPackedRevisionBlockNumber(bytes32 id, uint offset) internal {
        // Get the slot.
        bytes32 slot = packedRevisionBlockNumbers[id][offset / 8];
        // Wipe the previous block number.
        slot &= ~bytes32(uint32(-1) * 2 ** ((offset % 8) * 32));
        // Insert the current block number.
        slot |= bytes32(uint32(block.number) * 2 ** ((offset % 8) * 32));
        // Store the slot.
        packedRevisionBlockNumbers[id][offset / 8] = slot;
    }

    /**
     * @dev Create a new blob revision.
     * @param id Id of the blob.
     * @param blob Blob that should be stored as the new revision.
     * @return revisionId The new revisionId.
     */
    function createNewRevision(bytes32 id, bytes blob) noValue isOwner(id) isUpdatable(id) external returns (uint revisionId) {
        // Increment the number of revisions.
        revisionId = ++blobInfo[id].numRevisions;
        // Store the block number.
        _setPackedRevisionBlockNumber(id, revisionId - 1);
        // Store the new blob in a log in the current block.
        logBlob(id, revisionId, blob);
    }

    /**
     * @dev Update a blob's latest revsion.
     * @param id Id of the blob.
     * @param blob Blob that should be stored as the latest revision.
     */
    function updateLatestRevision(bytes32 id,  bytes blob) noValue isOwner(id) isUpdatable(id) isNotEnforceRevisions(id) external {
        if (blobInfo[id].numRevisions == 0) {
            blobInfo[id].blockNumber = uint32(block.number);
        }
        else {
            _setPackedRevisionBlockNumber(id, blobInfo[id].numRevisions - 1);
        }
        // Store the new blob in a log in the current block.
        logBlob(id, blobInfo[id].numRevisions, blob);
    }

    /**
     * @dev Retract a blob's latest revision.
     * @param id Id of the blob.
     */
    function retractLatestRevision(bytes32 id) noValue isOwner(id) isUpdatable(id) isNotEnforceRevisions(id) hasRevisions(id) external {
        // Delete slot if empty
        if (blobInfo[id].numRevisions % 8 == 1) {
            delete packedRevisionBlockNumbers[id][blobInfo[id].numRevisions / 8];
        }
        // Log the retraction.
        logRetractRevision(id, blobInfo[id].numRevisions--);
    }

    /**
     * @dev Delete all of a blob's packed revision block numbers.
     * @param id Id of the blob.
     */
    function _deleteAllRevisionBlockNumbers(bytes32 id) internal {
        uint numSlots = (blobInfo[id].numRevisions + 7) / 8;
        for (uint i = 0; i < numSlots; i++) {
            delete packedRevisionBlockNumbers[id][i];
        }
    }

    /**
     * @dev Delete all a blob's revisions and replace it with a new blob.
     * @param id Id of the blob.
     * @param blob Blob that should be stored.
     */
    function restart(bytes32 id, bytes blob) noValue isOwner(id) isUpdatable(id) isNotEnforceRevisions(id) external {
        // Try to get some gas refunds.
        _deleteAllRevisionBlockNumbers(id);
        // Update the blob state info.
        blobInfo[id].blockNumber = uint32(block.number);
        blobInfo[id].numRevisions = 0;
        // Store the blob in a log in the current block.
        logBlob(id, 0, blob);
    }

    /**
     * @dev Retract a blob.
     * @param id Id of the blob.
     */
    function retract(bytes32 id) noValue isOwner(id) isRetractable(id) external {
        // Delete the packed revision block numbers.
        _deleteAllRevisionBlockNumbers(id);
        // Mark this blob as retracted.
        blobInfo[id] = BlobInfo({
            updatable: false,
            enforceRevisions: false,
            retractable: false,
            transferable: false,
            numRevisions: 0,
            blockNumber: uint32(-1),
            owner: 0,
        });
        // Log that the blob has been retracted.
        logRetract(id);
    }

    /**
     * @dev Enable transfer of the blob to the current user.
     * @param id Id of the blob.
     */
    function transferEnable(bytes32 id) noValue isTransferable(id) external {
        // Record in state that the current user will accept this blob.
        enabledTransfers[id][msg.sender] = true;
    }

    /**
     * @dev Disable transfer of the blob to the current user.
     * @param id Id of the blob.
     */
    function transferDisable(bytes32 id) noValue isTransferEnabled(id, msg.sender) external {
        // Record in state that the current user will not accept this blob.
        enabledTransfers[id][msg.sender] = false;
    }

    /**
     * @dev Transfer a blob to a new user.
     * @param id Id of the blob.
     * @param recipient Address of the user to transfer to blob to.
     */
    function transfer(bytes32 id, address recipient) noValue isOwner(id) isTransferable(id) isTransferEnabled(id, recipient) external {
        // Update ownership of the blob.
        blobInfo[id].owner = recipient;
        // Disable this transfer in future and free up the slot.
        enabledTransfers[id][recipient] = false;
        // Log the transfer.
        logTransfer(id, recipient);
    }

    /**
     * @dev Disown a blob.
     * @param id Id of the blob.
     */
    function disown(bytes32 id) noValue isOwner(id) isTransferable(id) external {
        // Remove the owner from the blob's state.
        delete blobInfo[id].owner;
        // Log as blob as disowned.
        logDisown(id);
    }

    /**
     * @dev Set a blob as not updatable.
     * @param id Id of the blob.
     */
    function setNotUpdatable(bytes32 id) noValue isOwner(id) external {
        // Record in state that the blob is not updatable.
        blobInfo[id].updatable = false;
        // Log that the blob is not updatable.
        logSetNotUpdatable(id);
    }

    /**
     * @dev Set a blob to enforce revisions.
     * @param id Id of the blob.
     */
    function setEnforceRevisions(bytes32 id) noValue isOwner(id) external {
        // Record in state that all changes to this blob must be new revisions.
        blobInfo[id].enforceRevisions = true;
        // Log that the blob now forces new revisions.
        logSetEnforceRevisions(id);
    }

    /**
     * @dev Set a blob to not be retractable.
     * @param id Id of the blob.
     */
    function setNotRetractable(bytes32 id) noValue isOwner(id) external {
        // Record in state that the blob is not retractable.
        blobInfo[id].retractable = false;
        // Log that the blob is not retractable.
        logSetNotRetractable(id);
    }

    /**
     * @dev Set a blob to not be transferable.
     * @param id Id of the blob.
     */
    function setNotTransferable(bytes32 id) noValue isOwner(id) external {
        // Record in state that the blob is not transferable.
        blobInfo[id].transferable = false;
        // Log that the blob is not transferable.
        logSetNotTransferable(id);
    }

    function getContractId() noValue constant external returns (bytes12 _contractId) {
        _contractId = contractId;
    }

    /**
     * @dev Get the block number for a specific blob revision.
     * @param id Id of the blob.
     * @param revisionId Id of the revision.
     * @return blockNumber Block number of the specified revision.
     */
    function _getRevisionBlockNumber(bytes32 id, uint revisionId) internal returns (uint blockNumber) {
        if (revisionId == 0) {
            blockNumber = blobInfo[id].blockNumber;
        }
        else {
            bytes32 slot = packedRevisionBlockNumbers[id][(revisionId - 1) / 8];
            blockNumber = uint32(uint256(slot) / 2 ** (((revisionId - 1) % 8) * 32));
        }
    }

    /**
     * @dev Get info about a blob.
     * @param id Id of the blob.
     * @return owner Owner of the blob.
     * @return numRevisions How many revisions the blob has.
     * @return latestBlockNumber The block number of the latest revision.
     * @return updatable Is the blob updatable?
     * @return enforceRevisions Does the blob enforce revisions?
     * @return retractable Is the blob retractable?
     * @return transferable Is the blob transferable?
     */
    function getInfo(bytes32 id) noValue exists(id) constant external returns (address owner, uint numRevisions, uint latestBlockNumber, bool updatable, bool enforceRevisions, bool retractable, bool transferable) {
        owner = blobInfo[id].owner;
        numRevisions = blobInfo[id].numRevisions;
        latestBlockNumber = _getRevisionBlockNumber(id, numRevisions);
        updatable = blobInfo[id].updatable;
        enforceRevisions = blobInfo[id].enforceRevisions;
        retractable = blobInfo[id].retractable;
        transferable = blobInfo[id].transferable;
    }

    /**
     * @dev Get the owner of a blob.
     * @param id Id of the blob.
     * @return owner Owner of the blob.
     */
    function getOwner(bytes32 id) noValue exists(id) constant external returns (address owner) {
        owner = blobInfo[id].owner;
    }

    /**
     * @dev Is a blob updatable?
     * @param id Id of the blob.
     * @return updatable Is the blob updatable?
     */
    function getUpdatable(bytes32 id) noValue exists(id) constant external returns (bool updatable) {
        updatable = blobInfo[id].updatable;
    }

    /**
     * @dev Does a blob enforce revisions?
     * @param id Id of the blob.
     * @return enforceRevisions Does the blob enforce revisions?
     */
    function getEnforceRevisions(bytes32 id) noValue exists(id) constant external returns (bool enforceRevisions) {
        enforceRevisions = blobInfo[id].enforceRevisions;
    }

    /**
     * @dev Is a blob retractable?
     * @param id Id of the blob.
     * @return retractable Is the blob retractable?
     */
    function getRetractable(bytes32 id) noValue exists(id) constant external returns (bool retractable) {
        retractable = blobInfo[id].retractable;
    }

    /**
     * @dev Is a blob transferable.
     * @param id Id of the blob.
     * @return transferable Is the blob transferable?
     */
    function getTransferable(bytes32 id) noValue exists(id) constant external returns (bool transferable) {
        transferable = blobInfo[id].transferable;
    }

    /**
     * @dev Get the number of revisions a blob has.
     * @param id Id of the blob.
     * @return numRevisions How many revisions the blob has.
     */
    function getNumRevisions(bytes32 id) noValue exists(id) constant external returns (uint numRevisions) {
        numRevisions = blobInfo[id].numRevisions;
    }

    /**
     * @dev Get the block number for a specific blob revision.
     * @param id Id of the blob.
     * @param revisionId Id of the revision.
     * @return blockNumber Block number of the specified revision.
     */
    function getRevisionBlockNumber(bytes32 id, uint revisionId) noValue exists(id) revisionExists(id, revisionId) constant returns (uint blockNumber) {
        blockNumber = _getRevisionBlockNumber(id, revisionId);
    }

    /**
     * @dev Default function.
     */
    function() {
        throw;      // Do not maintain a balance.
    }

}

/**
 * @title BlobStore
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract BlobStore {

    struct BlobInfo {               // Single slot.
        bool updatable;             // Can the blob be updated? Can be disabled.
        bool enforceRevisions;      // When updating, always make a new revision. Can be enabled.
        bool retractable;           // Can the blob be retracted? Can be disabled.
        bool transferable;          // Can the blob be transfered to another user or disowned? Can be disabled.
        uint32 blockNumber;         // Which block has revision 0 of this blob.
        uint32 numRevisions;        // Number of additional revisions.
        address owner;              // Who owns this blob.
    }

    mapping (bytes32 => BlobInfo) blobInfo;
    mapping (bytes32 => mapping (uint => bytes32)) packedRevisionBlockNumbers;
    mapping (bytes32 => mapping (address => bool)) enabledTransfers;

    event logBlob(bytes32 indexed id, uint indexed revisionId, bytes blob);     // Greatest revisionId for the blob at time of logging.
    event logRetractRevision(bytes32 indexed id, uint revisionId);
    event logRetract(bytes32 indexed id);
    event logTransfer(bytes32 indexed id, address recipient);
    event logDisown(bytes32 indexed id);
    event logSetNotUpdatable(bytes32 indexed id);
    event logSetEnforceRevisions(bytes32 indexed id);
    event logSetNotRetractable(bytes32 indexed id);
    event logSetNotTransferable(bytes32 indexed id);

    // Create a 96-bit id for this contract. This is unique across all blockchains.
    // Wait a few minutes after deploying for this id to settle.
    bytes12 constant contractId = bytes12(sha3(this, block.blockhash(block.number - 1)));

    /**
     * @dev Throw if the current message is sending a payment.
     */
    modifier noValue() {
        if (msg.value > 0) {
            throw;      // Do not maintain a balance.
        }
        _
    }

    /**
     * @dev Throw if the blob has not been used before or it has been retracted.
     * @param id Id of the blob.
     */
    modifier exists(bytes32 id) {
        if (blobInfo[id].blockNumber == 0 || blobInfo[id].blockNumber == uint32(-1)) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the owner of the blob is not the message sender.
     * @param id Id of the blob.
     */
    modifier isOwner(bytes32 id) {
        if (blobInfo[id].owner != msg.sender) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the blob is not updatable.
     * @param id Id of the blob.
     */
    modifier isUpdatable(bytes32 id) {
        if (!blobInfo[id].updatable) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the blob is not enforcing revisions.
     * @param id Id of the blob.
     */
    modifier isNotEnforceRevisions(bytes32 id) {
        if (blobInfo[id].enforceRevisions) {
            throw;
        }
        _
    }

    /**
     * @dev Throw is the blob is not retractable.
     * @param id Id of the blob.
     */
    modifier isRetractable(bytes32 id) {
        if (!blobInfo[id].retractable) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the blob is not transferable.
     * @param id Id of the blob.
     */
    modifier isTransferable(bytes32 id) {
        if (!blobInfo[id].transferable) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the blob is not transferable to a specific user.
     * @param id Id of the blob.
     * @param recipient Address of the user.
     */
    modifier isTransferEnabled(bytes32 id, address recipient) {
        if (!enabledTransfers[id][recipient]) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if the blob does not have revisions.
     * @param id Id of the blob.
     */
    modifier hasRevisions(bytes32 id) {
        if (blobInfo[id].numRevisions == 0) {
            throw;
        }
        _
    }

    /**
     * @dev Throw if a specific blob revision does not exist.
     * @param id Id of the blob.
     * @param revisionId Id of the revision.
     */
    modifier revisionExists(bytes32 id, uint revisionId) {
        if (revisionId > blobInfo[id].numRevisions) {
            throw;
        }
        _
    }

    /**
     * @dev Stores new blob in the transaction log. It is guaranteed that each user will get a different id from the same nonce.
     * @param blob Blob that should be stored.
     * @param nonce Any value that the user has not used previously to create a blob.
     * @param updatable Should the blob be updatable?
     * @param enforceRevisions Should the blob enforce revisions when updating?
     * @param retractable Should the blob be retractable?
     * @param transferable Should the blob be transferable?
     * @param anon Should the blob be anonymous?
     * @return id Id of the blob.
     */
    function create(bytes blob, bytes32 nonce, bool updatable, bool enforceRevisions, bool retractable, bool transferable, bool anon) noValue external returns (bytes32 id) {
        // Determine the id.
        id = contractId | (sha3(msg.sender, nonce) & (2 ** 160 - 1));
        // Make sure this id has not been used before.
        if (blobInfo[id].blockNumber != 0) {
            throw;
        }
        // Store blob info in state.
        blobInfo[id] = BlobInfo({
            updatable: updatable,
            enforceRevisions: enforceRevisions,
            retractable: retractable,
            transferable: transferable,
            numRevisions: 0,
            blockNumber: uint32(block.number),
            owner: anon ? 0 : msg.sender,
        });
        // Store the blob in a log in the current block.
        logBlob(id, 0, blob);
    }

    /**
     * @dev Store a blob revision block number in a packed slot.
     * @param id Id of the blob.
     * @param offset The offset of the block number should be retreived.
     */
    function setPackedRevisionBlockNumber(bytes32 id, uint offset) internal {
        // Get the slot.
        bytes32 slot = packedRevisionBlockNumbers[id][offset / 8];
        // Wipe the previous block number.
        slot &= ~bytes32(uint32(-1) * 2 ** ((offset % 8) * 32));
        // Insert the current block number.
        slot |= bytes32(uint32(block.number) * 2 ** ((offset % 8) * 32));
        // Store the slot.
        packedRevisionBlockNumbers[id][offset / 8] = slot;
    }

    /**
     * @dev Create a new blob revision.
     * @param id Id of the blob.
     * @param blob Blob that should be stored as the new revision.
     * @return revisionId The new revisionId.
     */
    function createNewRevision(bytes32 id, bytes blob) noValue isOwner(id) isUpdatable(id) external returns (uint revisionId) {
        // Increment the number of revisions.
        revisionId = ++blobInfo[id].numRevisions;
        // Store the block number.
        setPackedRevisionBlockNumber(id, revisionId - 1);
        // Store the new blob in a log in the current block.
        logBlob(id, revisionId, blob);
    }

    /**
     * @dev Update a blob's latest revsion.
     * @param id Id of the blob.
     * @param blob Blob that should be stored as the latest revision.
     */
    function updateLatestRevision(bytes32 id,  bytes blob) noValue isOwner(id) isUpdatable(id) isNotEnforceRevisions(id) external {
        if (blobInfo[id].numRevisions == 0) {
            blobInfo[id].blockNumber = uint32(block.number);
        }
        else {
            setPackedRevisionBlockNumber(id, blobInfo[id].numRevisions - 1);
        }
        // Store the new blob in a log in the current block.
        logBlob(id, blobInfo[id].numRevisions, blob);
    }

    /**
     * @dev Retract a blob's latest revision.
     * @param id Id of the blob.
     */
    function retractLatestRevision(bytes32 id) noValue isOwner(id) isUpdatable(id) isNotEnforceRevisions(id) hasRevisions(id) external {
        // Delete slot if empty
        if (blobInfo[id].numRevisions % 8 == 1) {
            delete packedRevisionBlockNumbers[id][blobInfo[id].numRevisions / 8];
        }
        // Log the retraction.
        logRetractRevision(id, blobInfo[id].numRevisions--);
    }

    /**
     * @dev Delete all of a blob's packed revision block numbers.
     * @param id Id of the blob.
     */
    function deleteAllRevisionBlockNumbers(bytes32 id) internal {
        uint numSlots = (blobInfo[id].numRevisions + 7) / 8;
        for (uint i = 0; i < numSlots; i++) {
            delete packedRevisionBlockNumbers[id][i];
        }
    }

    /**
     * @dev Delete all a blob's revisions and replace it with a new blob.
     * @param id Id of the blob.
     * @param blob Blob that should be stored.
     */
    function restart(bytes32 id, bytes blob) noValue isOwner(id) isUpdatable(id) isNotEnforceRevisions(id) external {
        // Try to get some gas refunds.
        deleteAllRevisionBlockNumbers(id);
        // Update the blob state info.
        blobInfo[id].blockNumber = uint32(block.number);
        blobInfo[id].numRevisions = 0;
        // Store the blob in a log in the current block.
        logBlob(id, 0, blob);
    }

    /**
     * @dev Retract a blob.
     * @param id Id of the blob.
     */
    function retract(bytes32 id) noValue isOwner(id) isRetractable(id) external {
        // Delete the packed revision block numbers.
        deleteAllRevisionBlockNumbers(id);
        // Mark this blob as retracted.
        blobInfo[id] = BlobInfo({
            updatable: false,
            enforceRevisions: false,
            retractable: false,
            transferable: false,
            numRevisions: 0,
            blockNumber: uint32(-1),
            owner: 0,
        });
        // Log that the blob has been retracted.
        logRetract(id);
    }

    /**
     * @dev Enable transfer of the blob to the current user.
     * @param id Id of the blob.
     */
    function transferEnable(bytes32 id) noValue isTransferable(id) external {
        // Record in state that the current user will accept this blob.
        enabledTransfers[id][msg.sender] = true;
    }

    /**
     * @dev Disable transfer of the blob to the current user.
     * @param id Id of the blob.
     */
    function transferDisable(bytes32 id) noValue isTransferEnabled(id, msg.sender) external {
        // Record in state that the current user will not accept this blob.
        enabledTransfers[id][msg.sender] = false;
    }

    /**
     * @dev Transfer a blob to a new user.
     * @param id Id of the blob.
     * @param recipient Address of the user to transfer to blob to.
     */
    function transfer(bytes32 id, address recipient) noValue isOwner(id) isTransferable(id) isTransferEnabled(id, recipient) external {
        // Update ownership of the blob.
        blobInfo[id].owner = recipient;
        // Disable this transfer in future and free up the slot.
        enabledTransfers[id][recipient] = false;
        // Log the transfer.
        logTransfer(id, recipient);
    }

    /**
     * @dev Disown a blob.
     * @param id Id of the blob.
     */
    function disown(bytes32 id) noValue isOwner(id) isTransferable(id) external {
        // Remove the owner from the blob's state.
        delete blobInfo[id].owner;
        // Log as blob as disowned.
        logDisown(id);
    }

    /**
     * @dev Set a blob as not updatable.
     * @param id Id of the blob.
     */
    function setNotUpdatable(bytes32 id) noValue isOwner(id) external {
        // Record in state that the blob is not updatable.
        blobInfo[id].updatable = false;
        // Log that the blob is not updatable.
        logSetNotUpdatable(id);
    }

    /**
     * @dev Set a blob to enforce revisions.
     * @param id Id of the blob.
     */
    function setEnforceRevisions(bytes32 id) noValue isOwner(id) external {
        // Record in state that all changes to this blob must be new revisions.
        blobInfo[id].enforceRevisions = true;
        // Log that the blob now forces new revisions.
        logSetEnforceRevisions(id);
    }

    /**
     * @dev Set a blob to not be retractable.
     * @param id Id of the blob.
     */
    function setNotRetractable(bytes32 id) noValue isOwner(id) external {
        // Record in state that the blob is not retractable.
        blobInfo[id].retractable = false;
        // Log that the blob is not retractable.
        logSetNotRetractable(id);
    }

    /**
     * @dev Set a blob to not be transferable.
     * @param id Id of the blob.
     */
    function setNotTransferable(bytes32 id) noValue isOwner(id) external {
        // Record in state that the blob is not transferable.
        blobInfo[id].transferable = false;
        // Log that the blob is not transferable.
        logSetNotTransferable(id);
    }

    function getContractId() noValue constant external returns (bytes12 _contractId) {
        _contractId = contractId;
    }

    /**
     * @dev Get info about a blob.
     * @param id Id of the blob.
     * @return owner Owner of the blob.
     * @return numRevisions How many revisions the blob has.
     * @return latestBlockNumber The block number of the latest revision.
     * @return updatable Is the blob updatable?
     * @return enforceRevisions Does the blob enforce revisions?
     * @return retractable Is the blob retractable?
     * @return transferable Is the blob transferable?
     */
    function getInfo(bytes32 id) noValue exists(id) constant external returns (address owner, uint numRevisions, uint latestBlockNumber, bool updatable, bool enforceRevisions, bool retractable, bool transferable) {
        owner = blobInfo[id].owner;
        numRevisions = blobInfo[id].numRevisions;
        latestBlockNumber = getRevisionBlockNumber(id, numRevisions);
        updatable = blobInfo[id].updatable;
        enforceRevisions = blobInfo[id].enforceRevisions;
        retractable = blobInfo[id].retractable;
        transferable = blobInfo[id].transferable;
    }

    /**
     * @dev Get the owner of a blob.
     * @param id Id of the blob.
     * @return owner Owner of the blob.
     */
    function getOwner(bytes32 id) noValue exists(id) constant external returns (address owner) {
        owner = blobInfo[id].owner;
    }

    /**
     * @dev Is a blob updatable?
     * @param id Id of the blob.
     * @return updatable Is the blob updatable?
     */
    function getUpdatable(bytes32 id) noValue exists(id) constant external returns (bool updatable) {
        updatable = blobInfo[id].updatable;
    }

    /**
     * @dev Does a blob enforce revisions?
     * @param id Id of the blob.
     * @return enforceRevisions Does the blob enforce revisions?
     */
    function getEnforceRevisions(bytes32 id) noValue exists(id) constant external returns (bool enforceRevisions) {
        enforceRevisions = blobInfo[id].enforceRevisions;
    }

    /**
     * @dev Is a blob retractable?
     * @param id Id of the blob.
     * @return retractable Is the blob retractable?
     */
    function getRetractable(bytes32 id) noValue exists(id) constant external returns (bool retractable) {
        retractable = blobInfo[id].retractable;
    }

    /**
     * @dev Is a blob transferable.
     * @param id Id of the blob.
     * @return transferable Is the blob transferable?
     */
    function getTransferable(bytes32 id) noValue exists(id) constant external returns (bool transferable) {
        transferable = blobInfo[id].transferable;
    }

    /**
     * @dev Get the number of revisions a blob has.
     * @param id Id of the blob.
     * @return numRevisions How many revisions the blob has.
     */
    function getNumRevisions(bytes32 id) noValue exists(id) constant external returns (uint numRevisions) {
        numRevisions = blobInfo[id].numRevisions;
    }

    /**
     * @dev Get the block number for a specific blob revision.
     * @param id Id of the blob.
     * @param revisionId Id of the revision.
     * @return blockNumber Block number of the specified revision.
     */
    function getRevisionBlockNumber(bytes32 id, uint revisionId) noValue exists(id) revisionExists(id, revisionId) constant returns (uint blockNumber) {
        if (revisionId == 0) {
            blockNumber = blobInfo[id].blockNumber;
        }
        else {
            bytes32 slot = packedRevisionBlockNumbers[id][(revisionId - 1) / 8];
            blockNumber = uint32(uint256(slot) / 2 ** (((revisionId - 1) % 8) * 32));
        }
    }

    /**
     * @dev Default function.
     */
    function() {
        throw;      // Do not maintain a balance.
    }

}